线程作为程序内部的多个执行流,相互之间是可以通讯的。线程间通讯可以通过多种方式来进行,例如:线程间可以共享变量来进行通讯,使每个线程根据共享变量的值进行操作和运算,当通过共享变量进行通讯时,通常需要引入同步控制, 线程间也可以通过 wati()、notify()和notifyAll()等方法进行通讯。 每一个类的对象的实例都有一个等待集合,当在该实例上调用wait()方法后,线程都会进入到该实例的等待集合中。 wait()、notify() 和 notifyAll()方法使类Object中定义的方法,由于Java中的类都是Object类的子类,因此,java语言中任何类都可以调用这些方法,但这些方法更多的使在多线程环境中使用。 wait()方法: wait()方法的调用的一般形式是: 对象名.wait(); 称作线程在对象上的等待,作用是把当前的线程放入对象的等待集合中。 wait()方法通常需要放入以synchronized()方法修饰的语句块或方法中,如果在synchronized外部调用wait()方法,运行时刻Java虚拟机会抛出IllegalMonitorStateException异常。 wait()方法通常被放到try{}catch() 语句块中,例如: try{ wait(); }catch(InterruptedException e){ e.printStackTrace(); } 当线程调用wait()方法后,Java虚拟机会让当前的线程进入到休眠状态,并释放对对象的同步锁的控制权,允许其他线程执行该同步代码,要唤醒该线程,需要在同一个对象上调用notify()或notifyAll()方法。 notify()方法: 线程不能一直在等待集合中,必须有方法对其进行唤醒,notify()方法可以对线程进行唤醒。 notify()方法调用的一般形式如下: 对象名.notify(); 当使用当前对象时,使用this作为当前对象的引用,故可以直接写成notify(); 当使用某个对象的notify()方法时,将从该对象的等待集合中选择一个等待的线程唤醒,唤醒的线程将从等待集合中删除。
notifyAll()方法: notifyAll()方法会将所有在等待集合中的线程唤醒,但由于所有的被唤醒的线程仍然要去争用synchronized锁,而synchronized锁具有排他性,最终只有一个线程获得该锁,进行执行状态,其他线程仍要继续等待。 notifyAll()方法调用一般形似如下: 对象名notifyAll(); 当使用当前对象时,使用this作为当前都对象的引用,故可以直接写成notifyAll(); notify() 和notifyAll()方法不需要放入try...catch...语句中,主要的区别是:notify是唤醒一个线程,而notifyAll()是唤醒该对象等待集合中的所有线程。 当只有一个线程等待,另一个线程通知时,建议使用notify(),当有多个线程等待时,建议使用notifyAll()。
Demo示例: 模拟单缓冲区的生产者和消费者问题。 分析:单缓冲区是指生产者和消费者之间只有一个缓冲区,故生产者生产一个数据后,即进入等待状态,直到消费者消费,消费者消费一个数据后同样进入等待状态,知道生产者生产数据。 //CubbyHole.java 作为一个可操作的对象(共享区域),需要定义 共享变量 和 缓冲区,通过共享变量的值进行操作 缓冲区 public class CubbyHole{ private int goods; private boolean empty;
public CubbyHole( ){ empty=true; } //从缓冲区取数据 public synchronized int get(){ while(empty){ try{ wait(); }catch(InterruptedException e){ e.printStackTrace(); } } System.out.println("消费者拿走了物品"+ goods ); empty =true; //此时唤醒生产者线程,抓紧生产 notify(); return goods; } //向缓冲区放入数据 public synchronized void put(int value){ while(!empty){ try{ //有产品时,就不需要生产,不需要放数据,线程等待 wait(); }catch(InterruptedException e){ e.printStackTrace(); } } goods = value; System.out.println("生产者生产了物品"+goods); empty=false; notify(); } } //生产者Producer public class Producer extends Thread{ private CubbyHole cubbyHole; public Producer(CubbyHole c){ this.cubbyHole =c; } public void run(){ for(int i=0;i<50;i++){ cubbyHole.put((int)(100*Math.random())); } } } //消费者Consumer public class Consumer extends Thread{ private CubbyHole cubbyHole; public Consumer( CubbyHole c){ this.cubbyHole =c; } public void run(){ for(int i=0;i<50;i++){ cubbyHole.get(); } } } //启动类 public class Index{ public static void main(String [] args){ CubbyHole c= new CubbyHole(); Producer producer = new Producer(c); producer.start(); Consumer consumer = new Consumer(c); consumer.start(); } }