以前讨论了线程之间的互斥,这里讨论线程之间的通信。线程之间的通信即A线程唤醒正在阻塞的其他线程,使其继续执行。最传统的方式即wait,notify,先上例子。
这里要实现的效果是A线程输出一次“AAA",然后B线程输出一下“BBB”,由于输出AAA或者BBB不是原子性操作(即输出不是一下子就能完成的,这期间CPU可能跑到其他线程上去执行)所以显然线程之间的互斥是必须的,我们这里使用synchronized关键字来解决线程之间的互斥。
public Class TheadCommunication1{ public synchronized void out(String str){ //这样做的目的纯粹是为了让其出现错误,以突出synchronized的作用。 for(char c :str.toCharArray()){ try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.print(c); } System.out.println(); } public static void main(String[] args) { final ThreadCommunication1 t = new ThreadCommunication1(); new Thread(new Runnable() { public void run() { for(int i=0;i<50;i++){ t.out("AAA"); } } }).start();; new Thread(new Runnable() { public void run() { for(int i=0;i<50;i++){ t.out("BBB"); } } }).start();; } }
上面的代码可以实现线程之间的互斥,即当A线程执行out方法时B线程被阻塞,但是他没有实现线程之间的通信,即当A线程执行完out方法之后,接下来并不一定是B线程执行,可能A线程继续执行,也就是无法实现A B线程交替输出。所以必须使用线程之间的通信,下面使用了wait notify来实现
public class ThreadCommunication2 { private boolean toggle = true; public synchronized void outA() { while(toggle){ try { wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } for(char c :"AAA".toCharArray()){ try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.print(c); } System.out.println(); toggle = true; notify(); } public synchronized void outB( ) { while(!toggle){ try { wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } for(char c :"BBB".toCharArray()){ try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.print(c); } System.out.println(); toggle = false; notify(); } public static void main(String[] args) { final ThreadCommunication2 t = new ThreadCommunication2(); new Thread(new Runnable() { public void run() { for(int i=0;i<50;i++){ t.outA(); } } }).start();; new Thread(new Runnable() { public void run() { for(int i=0;i<50;i++){ t.outB(); } } }).start();; } }
这里要解释一点为何用while不用if,if只判断一次而while判断多次,用while的原因是为了避免虚假唤醒,即有些线程可能会在不满足条件的时候虚假唤醒,所以用while能够避免这种情况。
这样就可以实现两个线程轮换的运行了。这里要加一点wait notify的解释。
wait notify必须用在synchronized代码块里(或者是方法),不然就会报错,wait也是获得的监视器,所以必须在同步代码块里。wait获得的监视器必须是synchronized同步的对象的监视器,如果捕获的是不同对象的监视器就会报错。所以只能这样:
//这样是可以的,因为synchronized和wait都是捕获的this(也就是当前对象)的监视器 synchronized void method1(){ wait(); ... } //这样也是可以的,都是捕获的lock的监视器 byte[] lock = new byte[0];//仅用于锁 void method2(){ synchronized(lock){ lock.wait(); ... } } 但是除了这两种情况交叉起来就会报错
但是仍然不完美,因为notify是唤醒任意一个阻塞的线程,这里我们只有两个线程,所以唤醒的那个阻塞的线程一定是我们期待执行的线程,但是如果我们有3个线程呢?我们怎么指定唤醒哪个呢?所以这个时候就不能用synchronized wait notify这套机制了,原因就是无法指定唤醒哪个线程。
假设有这样的一个需求:有三个线程ABC,A执行后B执行,然后C执行再A执行,这个时候就要用lock,condition类了。lock和之前的lock的用法一样,但是lock可以产生很多condition,调用condition的await和signal方法就相当于是之前的wait notify方法。但是区别的时就是可以区分多个不同的condition以指定哪个condition被唤醒,也就时执行哪个线程。上例子
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class ThreadCommunication3 { private int toggle = 1; Lock lock = new ReentrantLock(); Condition cA= lock.newCondition(); Condition cB= lock.newCondition(); Condition cC= lock.newCondition(); public void outA() { lock.lock(); try { while(toggle != 1){ try { cA.await(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } for(char c :"AAA".toCharArray()){ try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.print(c); } System.out.println(); toggle = 2; cB.signal();//唤醒B } finally { lock.unlock(); } } public void outB() { lock.lock(); try { while(toggle != 2){ try { cB.await(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } for(char c :"BBB".toCharArray()){ try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.print(c); } System.out.println(); toggle = 3; cC.signal();//唤醒C } finally { lock.unlock(); } } public void outC() { lock.lock(); try { while(toggle != 3){ try { cC.await(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } for(char c :"CCC".toCharArray()){ try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.print(c); } System.out.println(); toggle = 1; cA.signal();//唤醒B } finally { lock.unlock(); } } public static void main(String[] args) { final ThreadCommunication3 t = new ThreadCommunication3(); new Thread(new Runnable() { public void run() { for(int i=0;i<50;i++){ t.outA(); } } }).start();; new Thread(new Runnable() { public void run() { for(int i=0;i<50;i++){ t.outB(); } } }).start(); new Thread(new Runnable() { public void run() { for(int i=0;i<50;i++){ t.outC(); } } }).start();; } }
通过condition唤醒指定的线程就可以实现多个线程之间的通信了,并且可以执行唤醒的顺序。
相关推荐
Java并发编程---synchronized关键
62-Java并发编程实战62-Java并发编程实战62-Java并发编程实战62-Java并发编程实战62-Java并发编程实战62-Java并发编程实战62-Java并发编程实战62-Java并发编程实战62-Java并发编程实战62-Java并发编程实战62-Java...
Java并发编程---Thread类!!
B站楠哥JUC Java并发编程
Java并发编程-设计原则与模式 pdf格式
Java并发编程实践-电子书-01章.pdf Java并发编程实践-电子书-02章.pdf Java并发编程实践-电子书-03章.pdf Java并发编程实践-电子书-04章.pdf Java并发编程实践-电子书-05章.pdf Java并发编程实践-电子书-06章.pdf ...
Java并发编程-并发编程知识点总结.docx
java并发编程-超级大全整理
JAVA并发编程-2-线程并发工具类一、Fork/Join1、分而治之与工作密取2、使用标准范式3、Fork/Join的同步用法4、Fork/Join的异步用法二、CountDownLatch三、CyclicBarrier四、Semaphore信号量五、Exchanger ...
阿里专家级并发编程架构师级课程,完成课程的学习可以帮助同学们解决非常多的JAVA并发编程疑难杂症,极大的提高...├─04-并发编程-并发协同-2.mp4 ├─L03-并发编程-并发协同.pdf (5)\并发编程05;目录中文件数:2个 ├
Java并发编程原汁原味英文版,Doug Lea大神经典著作, 内容:Concurrency Models, design forces, Java Designing objects for concurrency Immutability, locking, state dependence, containment, splitting ...
java并发编程-从入门到精通,相当不错的文档,可以看看,高清
java并发编程pdf文档第二部分:Java并发编程实战.pdf、Java多线程编程核心技术.pdf、实战Java高并发程序设计.pdf
JAVA并发编程实践-中文-高清-带书签-完整版(Doug+Lea)JAVA并发编程实践-中文-高清-带书签-完整版(Doug+Lea)
Java并发编程系列- volatile;Java并发编程系列- volatile;Java并发编程系列- volatile;Java并发编程系列- volatile;Java并发编程系列- volatile;
03-JUC高并发编程-JUC概述和进程线程概念(2).mp4$ T/ H9 R! n2 l9 a b 04-JUC高并发编程-JUC概述和进程线程概念(3).mp4 05-JUC高并发编程-Synchronized复习和案例分析.mp4& R: O+ [6 A8 h1 L9 | 06-JUC高并发...
java并发编程实战源码 附有本书所有源码,maven 导入 eclipse或idea
java并发编程艺术java并发编程艺术java并发编程艺术java并发编程艺术java并发编程艺术
JAVA并发编程艺术 高清pdf : 1.并发变成的挑战 2. java并发机制的底层实现原理 3. java 内存模型 4. java并发编程基础 5.java中的锁。。。。。。。
JAVA并发编程实践中文版 英文版 原书源码 带书签 java_concurrency_in_practice.pdf 英文版还是不错的,但是中文版的译者典型的没有技术功底,介绍上说什么专家, 翻译的非常差劲,有些句子都不通顺,都不知道自己去...