在并发编程中,经常会遇到多个线程之间需要相互协作的情况,即并不是多个线程同时执行,而是按照一定的顺序循环执行的情况。
那么怎样去实现这种效果呢?这里介绍三种方案。
这里都以子线程循环10次,然后主线程循环10次,然后往复循环50次的思路来做例子。在下面的例子中flag代表一个共享变量。

一、synchronized+notify+wait+flag

public class communication01 {public static void main(String[] args){final besiness b=new besiness();new Thread(new Runnable() {@Overridepublic void run() {for(int i=1;i<=50;i++){b.sub(i);}}}).start();for (int i = 1; i <= 50; i++) {b.main(i);}}
}class besiness{private static  boolean flag=true;//flag为true时允许main访问,为false时允许suB访问public synchronized void main(int i){while(!flag){try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}for (int j = 1; j <= 10; j++) {System.out.println("main thread==" + j + ",loop of " + i);}flag=false;this.notify();}public  synchronized  void sub(int i){while (flag){try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}for (int j = 1; j <= 10; j++) {System.out.println("sub thread==" + j + ",loop of " + i);}flag=true;this.notify();}}
这种方案是通过对两个线程中分别要执行的方法加锁synchronized,保证每次执行main时不被sub打断,执行sub循环时,不被main打断。
这里采用了对象object的notify和wait来实现线程之间的通信。当main方法执行完成后,让执行main方法的线程等待,
等待sub方法执行完成后,通知(notify)main线程然后继续执行。这种方式有一个缺点,由于notify和wait使用的是Object的方法,
所以不能单独的让某个特定的线程收到通知或者让他等待,而在存在多个线程同时等待时,只能通过notifyAll来通知所有的线程。不够灵活。

二、lock+condition+flag

 public static void main(String[] args){final besiness b=new besiness();new Thread(new Runnable() {@Overridepublic void run() {for(int i=1;i<=50;i++){b.sub2(i);}}}).start();new Thread(new Runnable() {@Overridepublic void run() {for(int i=1;i<=50;i++){b.sub3(i);}}}).start();for (int i = 1; i <= 50; i++) {b.main(i);}}static  class besiness{private   int flag=1;//flag为true时允许main访问,为false时允许suB访问//condition1来控制main和sub2之间的循环通信Condition condition1=lock.newCondition() ;//condition2来控制sub2和sub3之间的循环通信Condition condition2=lock.newCondition() ;//condition1来控制main和sub3之间的循环通信Condition condition3=lock.newCondition() ;public  void main(int i){lock.lock();try{while(flag!=1){try {condition1.await();} catch (InterruptedException e) {e.printStackTrace();}}for (int j = 1; j <= 20; j++) {System.out.println("main thread==" + j + ",loop of " + i);}flag=2;condition2.signal();}finally {lock.unlock();}}public    void sub2(int i){lock.lock();try{while ( flag !=2){try {condition2.await();} catch (InterruptedException e) {e.printStackTrace();}}for (int j = 1; j <= 20; j++) {System.out.println("sub2 thread==" + j + ",loop of " + i);}flag=3;condition3.signal();}finally {lock.unlock();}}public    void sub3(int i){lock.lock();try{while ( flag !=3){try {condition3.await();} catch (InterruptedException e) {e.printStackTrace();}}for (int j = 1; j <= 20; j++) {System.out.println("sub3 thread==" + j + ",loop of " + i);}flag=1;condition1.signal();}finally {lock.unlock();}}}
这种方式是利用了Java5中提供的lock和condition,利用共享变量flag来实现线程之间的相互通信。同时在这个小例子中,相比上一个例子中增加了一个线程的循环。这是为了体现使用condition的优点。
使用condition可以非常灵活的去控制线程与线程之间的通信。因为在一个类中可以创建多个condition的实例,
我们可以通过condition不同的实例的signal和await方法来标识不同的两个线程之间相互通信的标识,而不是统一使用object的notify和wait方法了。
同时利用lock方法可以利用锁的重入机制实现更加灵活的锁的应用。可以在需要的时候加锁或解锁。
这样我们就可以实现多个线程之间的协调通信了。

三、semaphere+flag

    public static void main(String[] args){final besiness b=new besiness();new Thread(new Runnable() {@Overridepublic void run() {for(int i=1;i<=50;i++){b.sub(i);}}}).start();for (int i = 1; i <= 50; i++) {b.main(i);}}static class besiness{private  int  flag=1;final Semaphore sp=new Semaphore(1);//声明一个信号,共享一个资源,每次只能允许一个线程执行public  void main(int i){try {sp.acquire();while(flag!=1){sp.release();}for (int j = 1; j <= 10; j++) {System.out.println("main thread==" + j + ",loop of " + i);}flag=2;} catch (InterruptedException e) {e.printStackTrace();}finally {sp.release();}}public   void sub(int i){try{try {sp.acquire();} catch (InterruptedException e) {e.printStackTrace();}while (flag !=2){sp.release();}for (int j = 1; j <= 10; j++) {System.out.println("sub thread==" + j + ",loop of " + i);}flag=1;sp.release();}finally {sp.release();}}}

这里semaphere代表一个信号量,它可以指示共享资源的个数,也就是同时访问资源的线程个数。这里主要通过semaphere的acquire和release实现锁的功能从而实现线程之间的通信。
利用semaphere不仅可以实现多个线程协调循环通信,在必要时还可以控制同一时间访问资源的个数。更加的灵活和方便。

四、countdownLatch

package com.jihite;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class CountDownLatchTest {private static final int RUNNER_COUNT = 10;public static void main(String[] args) throws InterruptedException {final CountDownLatch begin = new CountDownLatch(1);final CountDownLatch end = new CountDownLatch(RUNNER_COUNT);final ExecutorService exec = Executors.newFixedThreadPool(10);for (int i = 0; i < RUNNER_COUNT; i++) {final int NO = i + 1;Runnable run = new Runnable() {@Overridepublic void run() {try {begin.await();Thread.sleep((long)(Math.random() * 10000));System.out.println("No." + NO + " arrived");} catch (InterruptedException e) {e.printStackTrace();} finally {end.countDown();}}};exec.submit(run);}System.out.println("Game Start ...");begin.countDown();end.await();
//        end.await(30, TimeUnit.SECONDS);System.out.println("Game Over.");exec.shutdown();}
}
以上是实习多个线程之间相互协调通信的几种方案。

【多线程】四种种方案实现多线程之间相互协作的通信相关推荐

  1. 多线程顺序执行四种方案

    一.方案一(join) public static void main(String[] args) {final Thread t1 = new Thread(() -> System.out ...

  2. linux多线程拷贝信号量运用于线程之间通讯遇到的printf问题

    linux多线程拷贝信号量运用于线程之间通讯遇到的printf问题 1.题目内容 使用多线程实现文件的拷贝,并使用进度条进行相应的显示 2.进度 以下代码实现了多线程完成文件的拷贝,但是在使用进度条实 ...

  3. 详情讲述Linux网络编程关注的问题丨epoll原理丨reactor模型丨三次挥手丨四次握手丨多线程丨单线程丨C/C++Linux丨C++后端开发

    90分钟搞懂linux网络编程关注的问题 1. 三次挥手,四次握手 2. epoll实现原理剖析 3. reactor模型封装 单线程.多线程以及多进程 视频讲解如下,点击观看: 详情讲述Linux网 ...

  4. 5天玩转C#并行和多线程编程 —— 第五天 多线程编程大总结

    5天玩转C#并行和多线程编程 -- 第五天 多线程编程大总结 5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 -- 第一天 认识Parallel 5天玩转C#并行和多线程编程 ...

  5. java多线程三之线程协作与通信实例

    多线程的难点主要就是多线程通信协作这一块了,前面笔记二中提到了常见的同步方法,这里主要是进行实例学习了,今天总结了一下3个实例: 1.银行存款与提款多线程实现,使用Lock锁和条件Condition. ...

  6. python模拟并发是多线程_Python并发编程之多线程

    目录 一 什么是线程 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程 线程顾名思义,就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程 车间负责把资 ...

  7. c语言多线程访问一个变量_多线程+高并发+操作系统+网络+基础+调优+源码等xmind图整理好了...

    前言 多线程并发问题,基本是面试必问的. 今年刚刚毕业准备找实习的同学或者经历过最近一段时间面试的朋友们,相应你们应该都有一个相同的问题被问到,那就是多线程与高并发 因为最近和腾讯.阿里包括字节和京东 ...

  8. python多线程并发_Python并发之多线程

    线程 线程(Thread)也叫轻量级进程,是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属的一个 ...

  9. 人之间的尊重是相互的_人与人之间相互尊重的古语

    1.人与人之间互相尊重关爱的名言 一.尊重的表示,对那些富于高尚思想和有荣誉感的人有很大的力量. 出自:[古希腊]德谟克利特:<著作残篇> 介绍:德谟克利特,出生在色雷斯海滨的阿布德拉的商 ...

最新文章

  1. 阿里云首席架构师唐洪:拥抱开源的云端更具生命力
  2. 装oracle非常卡吗,win7系统安装完oracle电脑变卡的解决方法
  3. spark应用程序转换_打包并提交运行Spark应用程序jar包
  4. 2017.2.12【初中部 GDKOI】模拟赛B组 T4:pot
  5. linux 下基于jrtplib库的实时传送实现
  6. 解决方案仅用于执行startup.bat启动时乱码解决
  7. 官方一步解决各种Windows更新问题
  8. C语言计数排序Counting sort 算法(附完整源码)
  9. PHP操作文件和目录的相关函数
  10. 小甲鱼 OllyDbg 教程系列 (十五) : 逆向注册机简单算法
  11. Extjs 实现Iframe的子窗口遮罩整个页面
  12. c++ 退出函数_UCOSIII源码分析之——bsp_os.c文件分析
  13. IT技术支持必备知识
  14. 浅谈论文查重检测过程中的常见问题
  15. 电厂计算机监控系统的结构及功能,水电厂计算机监控系统
  16. LaTeX写数学公式
  17. Revealing Module(揭示模块)模式
  18. clock()、time()、clock_gettime()和gettimeofday()函数的用法和区别【转】
  19. vlan 虚拟局域⽹
  20. 微信气泡主题设置_微信气泡主题怎么设置_微信气泡主题怎么设置方法_掌通手游...

热门文章

  1. BT和eMule下载协议的比较和分析
  2. 信号调理(信号调理)
  3. html5笔迹画图,html5绘图工具canvas模拟笔迹绘画特效
  4. 涅槃重生,力荐大型分布式手册,凤凰架构让你浴火成神,良心分享
  5. pads查看pcb软件
  6. 思科vPC (Virtual Por Channel)
  7. 计算机专业在线杂志,计算机类的cscd期刊汇总
  8. 随机过程4-宽平稳过程,严平稳过程的定义和判定
  9. 【第66篇】行人属性识别研究综述(一)
  10. 小技巧|CSS如何实现文字两端对齐