本文通过wait(),notify(),notifyAll()模拟生产者-消费者例子,说明为什么使用notify()会发生死锁。
package com.example.hxk.thread.demo; import java.util.List; import java.util.concurrent.TimeUnit; /** * @author Smith 2019/3/21 */ public class Producer implements Runnable{ List<Integer> cache; public void put() throws InterruptedException { synchronized (cache) { while (cache.size() == 1) { try { cache.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } TimeUnit.SECONDS.sleep(1); cache.add(1); System.out.println(Thread.currentThread().getName() + "生产者生产了一条。"); cache.notify(); } } public Producer(List<Integer> cache) { this.cache = cache; } @Override public void run() { while (true) { try { put(); } catch (InterruptedException e) { e.printStackTrace(); } } } } 复制代码
package com.example.hxk.thread.demo; import java.util.List; /** * @author Smith 2019/3/21 */ public class Customer implements Runnable { List<Integer> cache; public Customer(List<Integer> cache) { this.cache = cache; } private void custom() { synchronized (cache) { while (cache.size() == 0) { try { cache.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } cache.remove(0); System.out.println(Thread.currentThread().getName() + "消费者消费了一条。"); cache.notify(); } } @Override public void run() { while (true) { custom(); } } } 复制代码
package com.example.hxk.thread.demo; import java.util.ArrayList; import java.util.List; /** * @author Smith 2019/3/21 */ public class Test { public static void main(String[] args) { List<Integer> cache = new ArrayList<>(); new Thread(new Producer(cache), "P1").start(); new Thread(new Customer(cache), "C1").start(); } } 复制代码
使用notify且一个生产者一个消费者的情况下,生产和消费有条不紊的运行,没有任何问题。
package com.example.hxk.thread.demo; import java.util.ArrayList; import java.util.List; /** * @author Smith 2019/3/21 */ public class Test { public static void main(String[] args) { List<Integer> cache = new ArrayList<>(); new Thread(new Producer(cache), "P1").start(); new Thread(new Customer(cache), "C1").start(); new Thread(new Customer(cache), "C2").start(); } } 复制代码
使用notify且一个生产者两个消费者的情况下,生产了两次后,程序死锁了。
代码就不粘了。
程序又恢复了正常。
每个同步对象都有自己的锁池和等待池。
知道了2的知识后,上面的三个例子也就好解释了。
1.3.1:因为只有一个生产者和消费者,所以等待池中始终只有一个线程,要么就是生产者唤醒消费者,要么消费者唤醒生产者,所以程序可以成功跑起来;
1.3.2:举个可能的例子
1.3.3: notifyAll()后,不存在只唤醒同类线程的情况,故也就不会出现1.3.2死锁的情况。
作者:emailed 来源:CSDN 原文: blog.csdn.net/emailed/art…
作者:泡芙掠夺者 来源:简书 原文: www.jianshu.com/p/45626f4e0…