线程间通信
来源:互联网 发布:软件测试原理与实践 编辑:程序博客网 时间:2024/06/07 05:39
一:线程间通信
线程间通常需要通信协作来完成某项任务。在java中可通过wait,notify,和notifyAll方法实现线程间通信。二:wait,notify,和notifyAll方法说明
只能在同步方法或者同步块里才能调用这3个方法。因为只有在synchronized 方法或块中当前线程才占有锁,才有锁可以释放。若不满足这一条件,程序虽然仍能编译,但在运行时会出现IllegalMonitorStateException 异常。
1. wait()方法:
在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。该方法会释放对象上的锁,从而使得其他线程可以获得这个锁,因此该对象中的其他同步方法可以在wait期间被调用。
2. notify()方法
唤醒在此对象监视器(也叫锁)上等待的单个线程。调用notify() 方法导致解除阻塞的线程是从因调用该对象的 wait() 方法而阻塞的线程中随机选取的,我们无法预料哪一个线程将会被选择,所以编程时要特别小心,避免因这种不确定性而产生问题。
3. notifyAll()方法
notifyAll()方法和notify起到类似作用,区别在于,调用 notifyAll()方法将把因调用该对象的wait()方法而阻塞的所有线程一次性全部解除阻塞。当然,只有获得锁的那一个线程才能进入可执行状态。
三:线程间通信示例
写一个程序计算1到100的和,子线程负责计算,主线程返回结果。
(1)首先来一个错误的做法:
public class CommunicationTest {public static void main(String[] args) {Sub sub = new Sub();sub.start();/*try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}*/synchronized (sub) {// 主线程拥有sub对象的锁try {System.out.println("等待子线程完成计算......");sub.wait();// 主线程等待} catch (InterruptedException e) {e.printStackTrace();}System.out.println("计算结果是:" + sub.getResult());}}}class Sub extends Thread {private int result = 0;;public int getResult() {return result;}@Overridepublic void run() {synchronized (this) {// 计算1到100的和for (int i = 1; i <= 100; i++) {result += i;}System.out.println("我已经算好了!");notify();// 计算完毕,唤醒主线程}}}
说明:
1. 在main方法中调用sub.wait(),是让主线程等待,而不是子线程sub。
2. 该程序容易发生死锁,因为如果是线程sub先执行,并且在主线程调用wait方法之前,线程sub就调用了notify方法,那么当主线程调用wait方法后,由于线程sub不会再调用notify方法,因此主线程就会一直等待下去,从而导致死锁。打开注释,让主线程休眠,先让线程sub运行就能看到死锁效果。
(2)修改版本
public class CommunicationTest {public static void main(String[] args) {final Calculator caculator = new Calculator();// 子线程new Thread(new Runnable() {@Overridepublic void run() {caculator.caculate();}}).start();// 主线程System.out.println("计算结果是:" + caculator.getResult());}}class Calculator {private int result = 0;private boolean shouldCaculate = true;// 先计算public synchronized void caculate() {while (!shouldCaculate) {// 用while循环是为了防止假唤醒try {wait();} catch (InterruptedException e) {e.printStackTrace();}}for (int i = 1; i <= 100; i++) {result += i;}shouldCaculate = false;notify();}public synchronized int getResult() {while (shouldCaculate) {// 如果还没有计算,则等待try {wait();} catch (InterruptedException e) {e.printStackTrace();}}shouldCaculate = true;notify();return result;}}
说明:
修改版本将计算和返回结果的方法封装起来,并在封装的类中实现方法互斥,而不是在线程代码。此外,还用了一个布尔值判断是否已经计算过了,这样即使getResult方法在调用wait方法之前,caculate方法就调用了notify方法,也不会引起死锁,因为getResult发现已经计算了,就不会等待了。
- 线程同步--线程间通信
- 线程同步--线程间通信
- JAVASE线程---线程间通信
- JAVA线程-线程间通信
- 线程3:线程间通信
- 线程与线程间通信
- 线程间通信
- c#线程间通信
- VC 线程间通信
- 线程间通信 ManualResetEvent
- java 线程间通信
- android线程间通信
- VC 线程间通信
- 线程间通信方式
- QT---线程间通信
- Android线程间通信
- 线程间的通信
- linux线程间通信
- TI C6000系列DSP的流水线介绍和软件流水优化
- java的Serialization 机制
- Java关键字(key)
- 你最深爱的编程语言其实很烂
- 提高工作激情的九种方法
- 线程间通信
- ASP.NET截取上传视频,swf文件第一帧作为预览图片
- php 操作sqlite类。增删改查,pdo链接
- loadrunner运行场景时,常见错误及解决方法
- iOS Developer:真机测试
- Android演进路线图--TWaver矢量小试
- 理解Linux重定向
- 善假于物,利用工具2天开发一款完整新闻类iOS app
- BZOJ 3566 SHOI2014 概率充电器 树形期望DP