一、对于wait()和notify()的解释
void notify() Wakes up a single thread that is waiting on this object’s monitor. 唤醒等待获取锁资源的单个线程 void notifyAll() Wakes up all threads that are waiting on this object’s monitor. 唤醒等待获取锁资源的所有线程 void wait( ) Causes the current thread to wait until another thread invokes the notify() method or the notifyAll( ) method for this object. 释放出对象的锁资源,程序会阻塞在这里
二、使用wait()、notify()、notifyAll()应该要注意的地方
1、wait( ),notify( ),notifyAll( )都不属于Thread类,属于Object基础类,每个对象都有wait( ),notify( ),notifyAll( ) 的功能,因为每个对象都有锁
2、当需要调用wait( ),notify( ),notifyAll( )的时候,一定都要在synchronized里面,不然会报 IllegalMonitorStateException 异常,可以这样理解,在synchronized(object) {}里面的代码才能获取到对象的锁。
3、while循环里而不是if语句下使用wait,这样,会在线程暂停恢复后都检查wait的条件,并在条件实际上并未改变的情况下处理唤醒通知
4、调用obj.wait( )释放了obj的锁,程序就会阻塞在这里,如果后面被notify()或者notifyAll()方法呼唤醒了之后,那么程序会接着调用obj.wait()后面的程序。
5、notify()唤醒等待获取锁资源的单个线程,notifyAll( )唤醒等待获取锁资源的所有线程
6、当调用obj.notify/notifyAll后,调用线程依旧持有obj锁,其它线程仍无法获得obj锁,直到调用线程退出synchronized块或者在原有的obj调用wait释放锁,其它的线程才能起来
三、使用wait()、notify()、notifyAll()实现非阻塞式的消费者和生产者
package wait; import java.util.PriorityQueue; public class WaitAndNofityTest { public static final int COUNT = 5; //优先队列,消费者在这个队列里面消耗数据,生产者在这个里面生产数据 public PriorityQueue<Integer> queue = new PriorityQueue<Integer>(COUNT); public static void main(String[] args) { WaitAndNofityTest waitAndNofityTest = new WaitAndNofityTest(); Cus cus = waitAndNofityTest.new Cus(); Make make = waitAndNofityTest.new Make(); make.start(); cus.start(); } //消费者线程类 class Cus extends Thread { @Override public void run() { System.out.println("Cus queue size is:" + queue.size()); eatData(); } public void eatData() { while (true) { synchronized (queue) { System.out.println("go to eatData method size is:" + queue.size()); while (queue.size() == 0) { try { System.out.println("Cus start notify"); queue.notify(); System.out.println("Cus start wait"); queue.wait(); System.out.println("Cus wait after"); } catch (InterruptedException e) { queue.notify(); } } queue.poll(); System.out.println("Cus eatData after size is:" + queue.size()); } } } } //生产者线程类 class Make extends Thread { @Override public void run() { System.out.println("Make queue size is:" + queue.size()); addData(); } public void addData() { while (true) { synchronized (queue) { System.out.println("go to addData method size is:" + queue.size()); while (queue.size() == COUNT) { try { System.out.println("Make start notify"); queue.notify(); System.out.println("Make start wait"); queue.wait(); System.out.println("Make wait after"); } catch (InterruptedException e) { queue.notify(); } } queue.offer(5); System.out.println("Cus addData after size is:" + queue.size()); } } } } }
四、部分运行结果
Cus addData after size is:5 go to addData method size is:5 Make start notify Make start wait Cus wait after Cus eatData after size is:4 go to eatData method size is:4 Cus eatData after size is:3 go to eatData method size is:3 Cus eatData after size is:2 go to eatData method size is:2 Cus eatData after size is:1 go to eatData method size is:1 Cus eatData after size is:0 go to eatData method size is:0 Cus start notify Cus start wait Make wait after Cus addData after size is:1 go to addData method size is:1 Cus addData after size is:2 go to addData method size is:2 Cus addData after size is:3 go to addData method size is:3 Cus addData after size is:4 go to addData method size is:4 Cus addData after size is:5 go to addData method size is:5 Make start notify Make start wait Cus wait after Cus eatData after size is:4 go to eatData method size is:4 Cus eatData after size is:3 go to eatData method size is:3 Cus eatData after size is:2 go to eatData method size is:2 Cus eatData after size is:1 go to eatData method size is:1 Cus eatData after size is:0 go to eatData method size is:0 Cus start notify Cus start wait Make wait after Cus addData after size is:1 go to addData method size is:1 Cus addData after size is:2 go to addData method size is:2 Cus addData after size is:3 go to addData method size is:3 Cus addData after size is:4 go to addData method size is:4 Cus addData after size is:5 go to addData method size is:5 Make start notify Make start wait Cus wait after Cus eatData after size is:4 go to eatData method size is:4 Cus eatData after size is:3 go to eatData method size is:3 Cus eatData after size is:2 go to eatData method size is:2 Cus eatData after size is:1 go to eatData method siz
如果运行了不理解,你可以自己测试然后分析打印的数据,当然你也可以注释掉2个类里面的任意一个notify方法,然后看是什么效果,是不是和自己分析的结果一样,同样你也可以去掉第一类的wait方法试下,看执行notify方法后是synchronized执行完了呼唤其其它线程或则在调用wait方法之后释放锁后是否也会呼唤其线程?
五、用ArrayBlockingQueue实现阻塞式的生产者和消费者
package wait; import java.util.concurrent.ArrayBlockingQueue; public class BlockTest { private int COUNT = 5; private ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(COUNT); public static void main(String[] args) { BlockTest test = new BlockTest(); Make make = test.new Make(); Cus cus = test.new Cus(); make.start(); cus.start(); } class Cus extends Thread { @Override public void run() { eatData(); } private void eatData() { while (true) { try { queue.take(); System.out.println("队列取一个元素,队列剩余"+queue.size() + "元素"); } catch (InterruptedException e) { e.printStackTrace(); } } } } class Make extends Thread { @Override public void run() { addData(); } private void addData() { while(true){ try { queue.put(5); System.out.println("队列插入一个元素,队列剩余空间:" + (COUNT-queue.size())); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
六、部分运行结果
队列取一个元素,队列剩余4元素 队列取一个元素,队列剩余3元素 队列取一个元素,队列剩余2元素 队列取一个元素,队列剩余1元素 队列取一个元素,队列剩余0元素 队列插入一个元素,队列剩余空间:4 队列插入一个元素,队列剩余空间:3 队列插入一个元素,队列剩余空间:2 队列插入一个元素,队列剩余空间:1 队列插入一个元素,队列剩余空间:0 队列取一个元素,队列剩余4元素 队列取一个元素,队列剩余3元素 队列取一个元素,队列剩余2元素 队列取一个元素,队列剩余1元素 队列取一个元素,队列剩余0元素 队列插入一个元素,队列剩余空间:4 队列插入一个元素,队列剩余空间:3 队列插入一个元素,队列剩余空间:2 队列插入一个元素,队列剩余空间:1 队列插入一个元素,队列剩余空间:0 队列取一个元素,队列剩余4元素 队列取一个元素,队列剩余3元素 队列取一个元素,队列剩余2元素 队列取一个元素,队列剩余1元素 队列取一个元素,队列剩余0元素 队列插入一个元素,队列剩余空间:4 队列插入一个元素,队列剩余空间:3 队列插入一个元素,队列剩余空间:2 队列插入一个元素,队列剩余空间:1 队列插入一个元素,队列剩余空间:0 队列取一个元素,队列剩余4元素 队列取一个元素,队列剩余3元素 队列取一个元素,队列剩余2元素 队列取一个元素,队列剩余1元素 队列取一个元素,队列剩余0元素 队列插入一个元素,队列剩余空间:4 队列插入一个元素,队列剩余空间:3 队列插入一个元素,队列剩余空间:2 队列插入一个元素,队列剩余空间:1 队列插入一个元素,队列剩余空间:0 队列取一个元素,队列剩余4元素 队列取一个元素,队列剩余3元素 队列取一个元素,队列剩余2元素 队列取一个元素,队列剩余1元素 队列取一个元素,队列剩余0元素 队列插入一个元素,队列剩余空间:4 队列插入一个元素,队列剩余空间:3 队列插入一个元素,队列剩余空间:2 队列插入一个元素,队列剩余空间:1 队列插入一个元素,队列剩余空间:0 队列取一个元素,队列剩余4元素 队列取一个元素,队列剩余3元素 队列取一个元素,队列剩余2元素 队列取一个元素,队列剩余1元素 队列取一个元素,队列剩余0元素 队列插入一个元素,队列剩余空间:4 队列插入一个元素,队列剩余空间:3 队列插入一个元素,队列剩余空间:2 队列插入一个元素,队列剩余空间:1 队列插入一个元素,队列剩余空间:0 队列取一个元素,队列剩余4元素 队列取一个元素,队列剩余3元素 队列取一个元素,队列剩余2元素 队列取一个元素,队列剩余1元素 队列取一个元素,队列剩余0元素 队列插入一个元素,队列剩余空间:4 队列插入一个元素,队列剩余空间:3 队列插入一个元素,队列剩余空间:2 队列插入一个元素,队列剩余空间:1 队列插入一个元素,队列剩余空间:0 队列取一个元素,队列剩余4元素