以前讨论了线程之间的互斥,这里讨论线程之间的通信。线程之间的通信即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并发编程中的多线程协作机制 在 Java 并发编程中,多线程协作机制是非常重要的一部分。多线程协作机制是指在多线程编程中,多个线程之间如何协作、同步和通信,以达到共同完成某个任务的目的。Java 提供了多种...
Java并发编程-设计原则与模式 pdf格式
Java并发编程实践-电子书-01章.pdf Java并发编程实践-电子书-02章.pdf Java并发编程实践-电子书-03章.pdf Java并发编程实践-电子书-04章.pdf Java并发编程实践-电子书-05章.pdf Java并发编程实践-电子书-06章.pdf ...
JAVA并发编程-2-线程并发工具类一、Fork/Join1、分而治之与工作密取2、使用标准范式3、Fork/Join的同步用法4、Fork/Join的异步用法二、CountDownLatch三、CyclicBarrier四、Semaphore信号量五、Exchanger ...
本教程“java并发编程-从入门到精通”旨在帮助你深入理解这个领域,并逐步提升你的编程能力。 首先,我们要理解Java并发的基础概念。并发是指一个程序中同时执行的多个线程,这在多核或多处理器系统中尤为常见。...
阿里专家级并发编程架构师级课程,完成课程的学习可以帮助同学们解决非常多的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开发中的重要领域,特别是在多核处理器和分布式系统中,高效地利用并发可以极大地提升程序的性能和响应速度。以下是对标题和描述中所提及的几个知识点的详细解释: 1. **线程与并发** - **线程*...
《Java并发编程实战》是Java并发编程领域的一本经典著作,它深入浅出地介绍了如何在Java平台上进行高效的多线程编程。这本书的源码提供了丰富的示例,可以帮助读者更好地理解书中的理论知识并将其应用到实际项目中。...
【Java并发编程-并发容器1】 在Java的并发编程中,容器的线程安全是至关重要的。HashMap在多线程环境下可能导致CPU利用率极高,因为它不是线程安全的。HashTable虽然提供了线程安全,但其同步机制导致并发性能较低。...
《Java并发编程实战》这本书是关于Java语言中并发编程技术的经典著作。它详细介绍了如何在Java环境中有效地实现多线程程序和并发控制机制。在Java平台上,由于其本身提供了强大的并发编程支持,因此,掌握并发编程...
"java并发编程-构建块"这个主题涵盖了使程序能够同时处理多个任务的关键概念和技术。在这个主题下,我们将深入探讨Java中用于构建高效并发应用的核心工具和概念。 1. **线程**:Java中的线程是并发编程的基础,每个...
《Java并发编程艺术》这本书深入探讨了Java平台上的并发编程技术。并发编程是现代多核处理器环境下提升软件性能的关键手段,而Java语言提供了丰富的工具和API来支持这一领域。本书旨在帮助开发者理解和掌握如何在...
总结,Java并发编程涵盖了大量的概念和技术,包括线程的创建、同步、通信以及并发工具的使用。理解和掌握这些知识点,是成为一名合格的Java并发程序员的基础。在实际开发中,应结合具体场景选择合适的并发策略,以...
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并发编程实战》是一本深入探讨Java平台并发编程的权威指南。这本书旨在帮助开发者理解和掌握在Java环境中创建高效、可扩展且可靠的多线程应用程序的关键技术和实践。它涵盖了从基本概念到高级主题的广泛内容,...