一、对于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 {@Overridepublic 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 {@Overridepublic 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实现阻塞式的生产者和消费者
官方API
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 {@Overridepublic 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 {@Overridepublic 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元素