线程通信(1)
来源:互联网 发布:蔬菜网络采购平台 编辑:程序博客网 时间:2024/06/03 15:26
思考:一个线程修改了一个对象的值,而另一个线程感知其变化,然后进行相应的操作。整个过程开始于一个线程,执行终止于另一个线程。要如何用Java来实现这个功能呢?
等待/通知机制
等待/通知机制,是指一个线程A调用了对象O的wait()方法进入等待状态,而另一个线程B调用了对象O的notify()或者notifyAll()方法,线程A收到通知后从对象O的wait()方法返回,进而执行后续操作。上述两个线程通过对象O来完成交互,而对象上的wait()notify/notifyAll()的关系就如同开关信号一样,用来完成等待方和通知方之间的交互工作。
等待/通知的经典范式
先来看一个特殊的案例,假如俩个线程分别代表取钱者和存钱者,现在有一种特殊的要求,每当存钱者存一笔钱进去,取钱者就必须马上把钱全部取出来,不可以连续存两次,也不能连续取两次。
这就涉及到线程之间的通信,如下例子就使用了等待/通知的经典范式
public class Account{ //封装账户编号、账户余额两个成员变量 private String accountNo; private double balance; //标识账户中是否有存款 private boolean flag =false; //取方法 public synchronized void draw(double drawAmount){ //flag为假就代表没钱,取方法阻塞 if(!flag){ wait(); } else{ //执行取钱操作 balance -=drawAmount; System.out.println("账户余额为:"+balance); //将标识账户是否有余额的旗标设置成false flag = false; //唤醒其他线程 notifyAll(); } } //存方法 public synchronized void deposit(double depositAmount){ //flag为真代表有钱,存方法阻塞 if(flag){ wait(); } else{ //执行取钱操作 balance +=depositAmount; System.out.println("账户余额为:"+balance); //将标识账户是否有余额的旗标设置成true flag = true; //唤醒其他线程 notifyAll(); } } }
从以上例中可以提炼出等待/通知的经典范式,该范式分为两部分,分别针对等待方(消费者)和通知方(生产者)。
等待方遵循如下原则。
1)获取对象的锁。2)如果条件不满足,那么调用对象的wait()方法,被通知后仍要检查条件。3)条件满足则执行对应的逻辑。对应的伪代码如下。synchronized(对象) { while(条件不满足) { 对象.wait(); } 对应的处理逻辑}
通知方遵循如下原则。
1)获得对象的锁。2)改变条件。3)通知所有等待在对象上的线程。对应的伪代码如下。synchronized(对象) { 改变条件 对象.notifyAll();}
wait()方法与notify()方法的使用总结
1)对于使用synchronized修饰的同步方法,因为该类的默认实例(this)就是同步监视器,所以可以在同步方法中直接调用这三个方法。
2)对于使用synchronized修饰的同步代码块,同步监视器是synchronized后括号里的对象,所以必须使用该对象调用这三个方法。
3)使用wait()、notify()和notifyAll()时需要先对调用对象加锁。
4)调用wait()方法后,线程状态由RUNNING变为WAITING,并将当前线程放置到对象的等待队列。
5)notify()或notifyAll()方法调用后,等待线程依旧不会从wait()返回,需要调用notify()或notifAll()的线程释放锁之后,等待线程才有机会从wait()返回。
6)notify()方法将等待队列中的一个等待线程从等待队列中移到同步队列中,而notifyAll()方法则是将等待队列中所有的线程全部移到同步队列,被移动的线程状态由WAITING变为BLOCKED。
7)从wait()方法返回的前提是获得了调用对象的锁。从上述细节中可以看到,等待/通知机制依托于同步机制,其目的就是确保等待线程从wait()方法返回时能够感知到通知线程对变量做出的修改。
如果程序不使用synchronized关键字来保证同步,而是使用Lock对象来保证同步,则系统中不存在隐式的同步监视器,也就不能使用wait() ,notify(),notifyAll()方法来进行线程通行了。这时候就要使用condition类来替代wait(),notify()方法了。
线程通信 - Condition接口
- 线程通信(1)
- 线程通信模型(1)
- 【串口通信】--线程应用(1)
- 线程通信(一)
- 线程通信(二)
- 线程通信(2)
- 多线程(线程通信)
- 线程通信(3)
- 线程2:线程通信事件机制(单线程、两个线程、多个线程通信)
- Java线程总结(3):线程通信
- 线程通信 线程同步(未完待续)
- 线程通信练习(三个线程交替)
- 线程通信和进程通信区别(线程进程区别)
- 线程之间的通信1
- 线程间通信示例1
- 线程间通信(一)
- Java线程通信(二)
- 多线程(3)- 线程通信
- 服务管理(systemctl)
- java 读取excel
- linux lsof用法
- 策略模式
- 配置hibernate根据实体类自动建表功能
- 线程通信(1)
- fresco加载gif图片到99%卡住的bug
- JDBC基础2之DAO
- 大头鬼的第一篇博客--发现新大陆
- IntelliJ IDEA For Mac 快捷键
- Quartz定时器时间配置格式说明及案例
- 10分钟搞定Java带token验证的注册登录
- winform点击按钮弹出input对话框
- 周志华《机器学习》学习笔记1--绪论