java之wait()、notify()实现非阻塞的生产者和消费者

一、对于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实现阻塞式的生产者和消费者

官方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 {
         
        @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元素



猜你喜欢

转载自blog.csdn.net/u011068702/article/details/80904338
今日推荐