博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java核心知识点学习----多线程 倒计时记数器CountDownLatch和数据交换的Exchanger
阅读量:7119 次
发布时间:2019-06-28

本文共 7572 字,大约阅读时间需要 25 分钟。

本文将要介绍的内容都是Java5中的新特性,一个是倒计时记数器---CountDownLatch,另一个是用于线程间数据交换的Exchanger.

一.CountDownLatch

1.什么是CountDownLatch? 

倒计时计数器,调用CountDownLatch对象的CountDown()方法就将计数器减一,当计数到达0时,则所有等待者或者全部等待者开始执行.

2.如何用?

new CountDownLatch(1);

直接new,其构造函数必须传一个int类型的参数,参数的意思是:

count the number of times countDown must be invoked before threads can pass through await

大致可理解成,有一个门,有N个门闩,要想打开门必须把所有门闩都打开,对应到线程上是说在线程通过等待前必须要执行的倒计时操作.

3.举例

package com.amos.concurrent;import java.util.Random;import java.util.concurrent.CountDownLatch;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/** * @ClassName: Count_Down_Latch_Test * @Description: 倒计时学习* @author: amosli* @email:hi_amos@outlook.com* @date Apr 27, 2014 11:51:43 PM  */public class Count_Down_Latch_Test {    public static void main(String[] args) {        ExecutorService executorService = Executors.newCachedThreadPool();        final CountDownLatch countdownOrder = new CountDownLatch(1);// an order        final CountDownLatch countdownAnwser = new CountDownLatch(3);// anwser        for (int i = 0; i < 3; i++) {            Runnable runnable = new Runnable() {                public void run() {                    try {                        countdownOrder.await();                        System.out.println("线程" + Thread.currentThread().getName() + " 正准备接受命令");                        System.out.println("线程"+Thread.currentThread().getName()+" 已经接受命令!");                        Thread.sleep(new Random().nextInt(1000));                        System.out.println("线程"+Thread.currentThread().getName()+" 回应处理结果!");                        countdownAnwser.countDown();                    } catch (Exception e) {                        e.printStackTrace();                    }                }            };            executorService.execute(runnable);//启动线程池        }                               try {            Thread.sleep(new Random().nextInt(1000));            System.out.println("线程"+Thread.currentThread().getName()+" 即将下达命令!!");            countdownOrder.countDown();            System.out.println("线程"+Thread.currentThread().getName()+" 已经下达命令,正在等待返回结果!");            countdownAnwser.await();            System.out.println("线程"+Thread.currentThread().getName()+" 已经收到所有处理结果!");        } catch (InterruptedException e) {            e.printStackTrace();        }      }}

1).效果如下图所示:

2)程序说明

首先是创建了一个可缓存的线程池--->接着,创建两个CountDownLatch类,一个赋值为1,一个赋值为3;----->然后,执行一个for循环,在循环中,首先是实现了一个Runnable接口,然后,将Runnable接口加入到线程池中; 其中Runnable接口,首先是等待计数器为0,然后如果为0那么将计数器2的值减一,每循环一次减一,当第三次循环时,线程执行完毕;----->在Runnable接口中等待计数器为0,整个程序无法向下走,这时main方法,即主线程执行CountDown方法,计数器减一-------->最后等待所有的线程都执行完毕,返回最终的结果.

4.扩展--官方例子

package com.amos.concurrent;import java.util.concurrent.CountDownLatch;public class CountDownLatchTest {    public static void main(String[] args) {        try {            new CountDownLatchTest().new Driver().main();        } catch (InterruptedException e) {            e.printStackTrace();        }    }    class Driver { // ...        void main() throws InterruptedException {            CountDownLatch startSignal = new CountDownLatch(1);            CountDownLatch doneSignal = new CountDownLatch(3);            for (int i = 0; i < 3; ++i)                // create and start threads            new Thread(new worker(startSignal, doneSignal)).start();            dosomethingelse(); // don't let run yet            startSignal.countDown(); // let all threads proceed            dosomethingelse();            doneSignal.await(); // wait for all to finish        }        private void dosomethingelse() {            System.out.println("dosomethingelse...");        }    }    class worker implements Runnable {        private final CountDownLatch startsignal;        private final CountDownLatch donesignal;        worker(CountDownLatch startsignal, CountDownLatch donesignal) {            this.startsignal = startsignal;            this.donesignal = donesignal;        }        public void run() {            try {                startsignal.await();                dowork();                donesignal.countDown();            } catch (Exception ex) {            } // return;        }        void dowork() {            System.out.println("dowork....");        }    }}
View Code

跟上面例子差不多,首先都是设置一个等待,然后再调用计数器减一,执行最后的操作.

CountDownLatch很适用于跑步比赛,当发令枪一声令下,所有选手开始跑起来.

 

二.Exchanger

1.什么是Exchange?作用是什么?

用于实现两人之间的数据交换,每个人在完成一定的事务后想与对方交换数据;只有两人见面才会有交换.就像是情人间的约会,不见不散.

2.如何使用?

new Exchanger
<v>
();

这里用到了泛型,即可以指定任意格式的数据,基本类型,对象等等都可以.

这里要注意的是线程要成对出现才能进行数据交换.用来交换的方法为exchange(x); 

Parameters:

x the object to exchange

参数为要进行交换给对方的数据.

3.举例:

package com.amos.concurrent;import java.util.Random;import java.util.concurrent.Exchanger;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/** * @ClassName: ExchangerTest * @Description: 线程间的数据交换Exchanger* @author: amosli* @email:hi_amos@outlook.com* @date Apr 28, 2014 12:26:48 AM  */public class ExchangerTest {    public static void main(String[] args) {        final Exchanger
exchanger = new Exchanger
(); ExecutorService newCachedThreadPool = Executors.newCachedThreadPool(); //线程一 newCachedThreadPool.execute(new Runnable() { public void run() { try { String data1="111"; System.out.println("线程:"+Thread.currentThread().getName()+" 要换出去的数据为:"+data1); Thread.sleep(new Random().nextInt(1000)); String exchange = exchanger.exchange(data1); System.out.println("线程:"+Thread.currentThread().getName()+" 换回来的数据为:"+exchange); } catch (InterruptedException e) { e.printStackTrace(); } } }); //线程二 newCachedThreadPool.execute(new Runnable() { public void run() { try { String data1="hi_amos"; System.out.println("线程:"+Thread.currentThread().getName()+" 要换出去的数据为:"+data1); Thread.sleep(new Random().nextInt(1000)); String exchange = exchanger.exchange(data1); System.out.println("线程:"+Thread.currentThread().getName()+" 换回来的数据为:"+exchange); } catch (InterruptedException e) { e.printStackTrace(); } } }); }}

这里只需要注意使用exchange()方法即可.

效果:

4.扩展---官方例子

class FillAndEmpty {   Exchanger exchanger = new Exchanger();   DataBuffer initialEmptyBuffer = ... a made-up type   DataBuffer initialFullBuffer = ...   class FillingLoop implements Runnable {     public void run() {       DataBuffer currentBuffer = initialEmptyBuffer;       try {         while (currentBuffer != null) {           addToBuffer(currentBuffer);           if (currentBuffer.isFull())             currentBuffer = exchanger.exchange(currentBuffer);         }       } catch (InterruptedException ex) { ... handle ... }     }   }   class EmptyingLoop implements Runnable {     public void run() {       DataBuffer currentBuffer = initialFullBuffer;       try {         while (currentBuffer != null) {           takeFromBuffer(currentBuffer);           if (currentBuffer.isEmpty())             currentBuffer = exchanger.exchange(currentBuffer);         }       } catch (InterruptedException ex) { ... handle ...}     }   }   void start() {     new Thread(new FillingLoop()).start();     new Thread(new EmptyingLoop()).start();   } } }

官方的例子,也比较简单,启动两个线程,然后调用exchange()方法进行两个线程间的数据交换.

 

 

 

 

 

 

转载地址:http://gqnel.baihongyu.com/

你可能感兴趣的文章
[zt]OpenCV2.1.0的安装
查看>>
Elasticsearch——Search的基本介绍
查看>>
Vue v-bind的使用
查看>>
第 22 章 Beta
查看>>
Linux 监视文件、文件夹改动
查看>>
[Erlang 0079] RabbitMQ 初探
查看>>
36.5. height / width
查看>>
树莓派蜜罐节点部署实战
查看>>
交换知识 VLAN VTP STP 单臂路由
查看>>
svn 回滚到上一个版本shell 脚本
查看>>
UID 修改 & UID 锁死修复
查看>>
动手实践虚拟网络 - 每天5分钟玩转 OpenStack(10)
查看>>
(转) Deep Learning Resources
查看>>
Node.js 开发模式(设计模式)
查看>>
vs生成命令和属性的宏
查看>>
【Python】supervisor 工具介绍
查看>>
【MySQL】浅谈一致性读
查看>>
浅谈嵌入式软件的未来发展
查看>>
8.4. Socket 方式
查看>>
对于技术焦虑的一点想法
查看>>