Java多线程系列4(wait/notify/notifyAll)
来源:互联网 发布:数字青少年宫网络寄语 编辑:程序博客网 时间:2024/06/05 00:48
- waitnotifynotifyAll
- 实现生产者消费者模型
- 继续理解waitnotifynotifyAll
1 wait/notify/notifyAll
这三个方法是在java.lang.Object类提供的,使用的时候需要注意:
(1)这三个方法需要在synchronized方法或者同步快中调用;
(2)调用wait/notify/notifyAll的对象必须和synchronized对应的对象一致。也即如果synchronized(variableA),但是却使用variableB.wait()是不行的。
如果不遵循上面两个前提条件,会报错:
java.lang.IllegalMonitorStateException
wait:会导致当前线程进行等待,交出监视器的控制权,直到其他线程调用监视器的notify/notifyAll
notify:唤醒在监视器上等待的单个线程
notifyAll:唤醒在监视器上等待的所有线程
2 实现生产者/消费者模型
以下是使用wait/notify来实现的经典的生产者/消费者的代码示例:
public class test { public static class Product { private int maxSize; private List<String> productList = new ArrayList<>(); public Product() { this.maxSize = 10; } public void produceProduct() { synchronized (this) { while (productList.size() == maxSize) { try { wait(); } catch (InterruptedException e) { } } System.out.println("Produce product, Num = " + productList.size()); productList.add(productList.size() + ""); notify(); } } public void consumeProduct() { synchronized (this) { while (productList.size() == 0) { try { wait(); } catch (InterruptedException e) { } } System.out.println("Consume product, Num = " + productList.get(productList.size() - 1)); productList.remove(productList.size() -1); notify(); } } } public static class ConsumerThread implements Runnable { private Product product; public ConsumerThread(Product product) { this.product = product; } @Override public void run() { for (int i = 0; i < 50; i++) { try { Thread.sleep(100); } catch (InterruptedException e) { } product.consumeProduct(); } } } public static class ProduceThread implements Runnable { private Product product; public ProduceThread(Product product) { this.product = product; } @Override public void run() { for (int i = 0; i < 50; i++) { try { Thread.sleep(10); } catch (InterruptedException e) { } product.produceProduct(); } } } public static void main(String[] args) { Product product = new Product(); Thread consumer = new Thread(new ConsumerThread(product)); Thread producer = new Thread(new ProduceThread(product)); consumer.start(); producer.start(); try { consumer.join(); producer.join(); } catch (InterruptedException e) { } System.out.println("main therad exit"); }}
总结:
1)以上代码中使用Product的实例作为监视器,实际使用中也可以使用productList,或者使用新的变量Object lock = new Object(),都可以;
2)调用wait的对象,必须和监视器一样;
3)实现生产者/消费者模型时,执行wait/notify前提条件,一般都会写在 while循环中,这是为了防止,出现 InteruptedException时,条件还没有满足,就执行下面的任务了。
以上是实现生产者/消费者模型时,需要注意的问题。
3 继续理解wait/notify/notifyAll
在实际使用中,如果线程A调用wait进入Blocked状态,线程B在synchronized块(或者方法)中调用notify后,必须等到整个synchronized执行完毕以后,才会释放synchronized对象锁,这样后续线程A才能获得synchronized对象锁由Blocked状态变为Runnable,然后在wait点之后继续执行。
继续思考如下场景,能够更加透彻的理解
1)wait/notify:
基于同一个对象作为synchronized对象,如果有A/B/C三个线程调用了wait,进入阻塞状态。然后线程D调用notify,根据系统的调度,A/B/C中只会有一个线程会随机收到通知,收到通知的线程会被添加到synchronized锁对象的锁池中,在这个锁池中的线程会竞争synchronized锁,竞争到锁的线程会被移出锁池,继续执行wait之后的代码。
2)wait/notifyAll
和上面一样,唯一的差别是,当线程D调用notifyAll时,A/B/C三个线程都会收到通知,都会被添加到synchronized锁对象的锁池中,这个锁池中的线程会竞争synchronized锁,竞争到的锁的线程会被移出锁池,继续执行wait之后的代码。假设A竞争到锁,此时会执行A线程中wait之后的代码,执行完毕以后,释放锁以后,B/C继续继续竞锁,直到锁池中的线程都获得锁,执行完毕代码。
可见,当notify/notifyAll调用以后,wait不一定会立即执行,必须在调用notify/notifyAll的线程释放锁以后,wait的线程才有机会得到执行。
设计下面的线程便可看到效果:
public class test { private static Object lock = new Object(); private static long time = System.currentTimeMillis(); public static class Task extends Thread { public Task(String name) { super(name); } @Override public void run() { synchronized (lock) { try { lock.wait(); } catch (InterruptedException e) { } System.out.println("Task name:" + getName() + "; exexute time interval = " + (System.currentTimeMillis() - time)); } } } public static void main(String[] args) { Thread a = new Task("Thread-A"); Thread b = new Task("Thread-B"); Thread c = new Task("Thread-C"); a.start(); b.start(); c.start(); //main线程sleep 1s,等待县城A/B/C都调用wait方法等待 try { Thread.sleep(1000); } catch (InterruptedException e) { } time = System.currentTimeMillis(); synchronized (lock) { lock.notify(); //main线程执行notify之后,延迟10s才退出同步块,释放lock try { Thread.sleep(10000); } catch (InterruptedException e) { } } System.out.println("main therad exit"); }}
执行结果:
main therad exitTask name:Thread-A; exexute time interval = 10000
可以看到main线程执行notify以后,延迟10s才释放锁,A/B/C中A在10s以后才执行wait,这也证明了我们的分析。
- Java多线程系列4(wait/notify/notifyAll)
- java多线程(四)wait() notify() notifyall()
- java多线程wait() ,notify() notifyAll()
- Java多线程(九)——wait() notify() notifyAll()
- java多线程之 wait(),notify(),notifyAll()
- java多线程之 wait(),notify(),notifyAll() 整理
- Java多线程之wait(),notify(),notifyAll()
- java多线程之 wait(),notify(),notifyAll()[迁]
- Java多线程之wait(),notify(),notifyAll()
- Java多线程,wait()、notify()、notifyAll()详解
- Java多线程之wait(),notify(),notifyAll() .
- Java多线程之synchronized,wait(),notify(),notifyAll()
- Java多线程之wait(),notify(),notifyAll()
- Java多线程之wait(),notify(),notifyAll()
- Java多线程3:wait、notify和notifyAll
- Java多线程之wait(),notify(),notifyAll()
- JAVA多线程的理解wait、notify、notifyAll
- Java多线程之wait(),notify(),notifyAll()
- 提交表单无动于衷
- MinGw与Cygwin的区别
- ROS实战_1.5 ROS调试与可视化
- 简单排序Java实现(一):冒泡排序,选择排序,插入排序(原理及实现)
- c#之路1
- Java多线程系列4(wait/notify/notifyAll)
- JSP之JSTL标签-核心标签库
- job review: java面试--宏观要求
- centos 关闭firewall开启iptables
- 算法笔记 (4)算法的逻辑结构
- ubuntu和ROS
- LeetCode 169 Majority Element
- easyui树形菜单之hierbnate返回问题
- AD采集,PID控制与PWM的定量关系