在Java中,有两种实现多线程的方式:继承Thread类和实现Runnable接口。
Thread
此类的定义如下:
public class Thread extends Object implments Runnable
构造方法如下:
Thread(),Thread(Runnable target)
静态字段:
static int MAX_PRIORITY:线程可以具有的最高优先级
static int MIN_PRIORITY:线程可以具有的最低优先级
static int NORM_PRIORITY:分配给线程的默认优先级
主要方法:
public void start():启动线程,Java虚拟机调用该线程的run方法。
public static void sleep(long millis) throws InterruptedException:是线程休眠指定的毫秒
实例:
package com.fuwh.thread; public class ThreadTest01 { public static void main(String[] args) { System.out.println("线程最大优先级:"+Thread.MAX_PRIORITY); System.out.println("线程最小优先级:"+Thread.NORM_PRIORITY); System.out.println("线程默认优先级:"+Thread.MIN_PRIORITY); Thread t1=new Thread(); Thread t2=new Thread("线程二"); t1.setName("线程一"); System.out.println(t1.getName()+"的优先级:"+t1.getPriority()+";Id:"+t1.getId()); System.out.println(t2.getName()+"的优先级:"+t2.getPriority()+";Id:"+t2.getId()); } }
实例2:
package com.fuwh.thread; class MyThread extends Thread{ private String name; public MyThread(String name){ this.name=name; } @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<10;i++){ System.out.println(name+"线程运行 -- "+i); } } } public class ThreadTest02 { public static void main(String[] args) { MyThread mt1=new MyThread("线程一"); MyThread mt2=new MyThread("线程二"); mt1.start(); mt2.start(); } }
此时的线程已经实现了交互的运行了。
Runnable接口:
接口的定义如下:
public interface Runnable
此类中只有一个run()方法。使用Runnable接口的对象创建线程的时候,启动该线程,就导致该独立执行的线程会调用该接口中的run()方法。
实例:
package com.fuwh.thread; class MyRunnable implements Runnable{ private String name; public MyRunnable(String name){ this.name=name; } @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<10;i++){ System.out.println(name+"线程运行 -- "+i); } } } public class ThreadTest03 { public static void main(String[] args) { MyRunnable mt1=new MyRunnable("线程一"); MyRunnable mt2=new MyRunnable("线程二"); new Thread(mt1).start(); new Thread(mt2).start(); } }
那么,这两种实现方式有什么区别呢,首先,实现接口可以避免java单继承的问题,
其次,通过观察可以发现,如果以如下的方式启动多线程呢?
Runnable接口子类实例 ra=new Runnable接口子类实例 (); new Thread(ra).start(); new Thread(ra).start();
则此时,两个线程在启动之后调用的都是ra实例的run方法,则可以达到资源共享的目的。
实例:
package com.fuwh.thread; class SellTicket implements Runnable{ private int ticketCount=50; @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<50;i++){ if(this.ticketCount>0){ System.out.println("售票一张,余票:"+this.ticketCount--); } } } } public class ThreadTest04 { public static void main(String[] args) { SellTicket st=new SellTicket(); new Thread(st,"卖票点1").start(); new Thread(st,"卖票点2").start(); } }
但是,此时 仍然存在一个问题,倘若只剩最后一张票的时候,线程一去判断,还有一张票,于是准备去执行卖票,这时候线程二来了,发现也还有一张票,也准备去执行卖票,这时候,就会导致线程一和线程二都会去执行卖票操作,导致多卖一张票。
这时候,就需要引入线程的同步和死锁概念。
同步与死锁
在java中,要实现同步有两种方式:同步代码块和同步方法
同步代码块修改上述实例:
package com.fuwh.thread; class SellTicket implements Runnable{ private int ticketCount=10; @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<50;i++){ synchronized (this) { if(this.ticketCount>0){ try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("售票一张,余票:"+this.ticketCount--); } } } } } public class ThreadTest04 { public static void main(String[] args) { SellTicket st=new SellTicket(); new Thread(st,"卖票点1").start(); new Thread(st,"卖票点2").start(); } }
同步方法修改:
package com.fuwh.thread; class SellTicket implements Runnable{ private int ticketCount=10; @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<50;i++){ this.sellTicket(); } } public synchronized void sellTicket(){ if(this.ticketCount>0){ try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("售票一张,余票:"+this.ticketCount--); } } } public class ThreadTest06 { public static void main(String[] args) { SellTicket st=new SellTicket(); new Thread(st,"卖票点1").start(); new Thread(st,"卖票点2").start(); } }
死锁:
死锁就是说当两个线程在互相等待的时候,就会出现死锁。