本文将要介绍的内容都是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....");
}
} }

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

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<String> exchanger = new Exchanger<String>(); 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()方法进行两个线程间的数据交换.

Java核心知识点学习----多线程 倒计时记数器CountDownLatch和数据交换的Exchanger的更多相关文章

  1. Java核心知识点学习----多线程中的阻塞队列,ArrayBlockingQueue介绍

    1.什么是阻塞队列? 所谓队列,遵循的是先进先出原则(FIFO),阻塞队列,即是数据共享时,A在写数据时,B想读同一数据,那么就将发生阻塞了. 看一下线程的四种状态,首先是新创建一个线程,然后,通过s ...

  2. java核心知识点学习----多线程间的数据共享和对象独立,ThreadLocal详解

    线程内的数据共享与对象独立,举例:张三给李四转钱,开启A线程去执行转钱这个动作,刚好同时王五给赵六转钱,开启B线程去执行转钱,因为是调用的同样一个动作或者说对象,所以如果不能保证线程间的对象独立,那么 ...

  3. java核心知识点学习----多线程并发之线程同步

    1.什么是线程同步? 多线程编程是很有趣的事情,它很容易出现"错误情况",这种情况不是由编码造成的,它是由系统的线程调度造成的,当使用多个线程来访问同一个数据时,很容易出现&quo ...

  4. java核心知识点学习----多线程间的数据共享的几种实现方式比较

    需求:设计4个线程,其中两个线程每次对j增加1,另外两个线程对j减少1. 实现数据共享的几种方式比较: 1.使用同一个runnable对象 如果每个线程执行的代码相同,那么可以使用同一个runnabl ...

  5. Java核心知识点学习----多线程并发之线程间的通信,notify,wait

    1.需求: 子线程循环10次,主线程循环100次,这样间隔循环50次. 2.实现: package com.amos.concurrent; /** * @ClassName: ThreadSynch ...

  6. Java核心知识点学习----使用Condition控制线程通信

    一.需求 实现线程间的通信,主线程循环3次后,子线程2循环2次,子线程3循环3次,然后主线程接着循环3次,如此循环3次. 即:A->B->C---A->B->C---A-> ...

  7. Java核心知识点学习----线程中如何创建锁和使用锁 Lock,设计一个缓存系统

    理论知识很枯燥,但这些都是基本功,学完可能会忘,但等用的时候,会发觉之前的学习是非常有意义的,学习线程就是这样子的. 1.如何创建锁? Lock lock = new ReentrantLock(); ...

  8. java核心知识点学习----重点学习线程池ThreadPool

    线程池是多线程学习中需要重点掌握的. 系统启动一个新线程的成本是比较高的,因为它涉及与操作系统交互.在这种情形下,使用线程池可以很好的提高性能,尤其是当程序中需要创建大量生存期很短暂的线程时,更应该考 ...

  9. java核心知识点学习----创建线程的第三种方式Callable和Future CompletionService

    前面已经指出通过实现Runnable时,Thread类的作用就是将run()方法包装成线程执行体,那么是否可以直接把任意方法都包装成线程执行体呢?Java目前不行,但其模仿者C#中是可以的. Call ...

随机推荐

  1. C#特性学习笔记一

    元数据,就是C#中封装的一些类,无法修改.类成员的特性被称为元数据中的注释. 1.什么是特性   1)属性与特性的区别 属性(Property):属性是面向对象思想里所说的封装在类里面的数据字段,Ge ...

  2. VS xsd Class

    1.将xsd 文件 转成   实体文件 xsd  FilePath(*.xsd)   /c 2.将 xml 文件 转成  xsd  文件 xsd  FilePath(*.xml)

  3. Windows性能查看器:系统的性能信息(I/O,IIS最大连接数,Sql) ,以及解决 asp.net IIS 一二百多用户并发

    在测试过程中,我们经常需要知道“系统的资源利用情况”来监测我们的测试执行情况,来查看测试环境是否有效,测试结果是否可信,或者是在无人值守时保存结果,等我们值班时再来分析. 1.在Windows环境下, ...

  4. 【mysql元数据库】使用information_schema.tables查询数据库和数据表信息

    概述 对于mysql和Infobright等数据库,information_schema数据库中的表都是只读的,不能进行更新.删除和插入等操作,也不能加触发器,因为它们实际只是一个视图,不是基本表,没 ...

  5. swoole和erlang通信测试

    直接用docker跑环境 docker pull xlight/docker-php7-swoole docker run -it -v ~/Projects/php/swoole:/workdir ...

  6. 使用 Windows AIK 创建自定的客户端系统WIM文件

    Windows 7/2008 的AIK 3.0下载页面:地址链接 1.8G [3.1补充包为1.4G] 安装3.0后,升级为3.1方法: xcopy E:\ "C:\Program File ...

  7. 写MYSQL存储过程遇到的一个小BUG

    DELIMITER $$ USE `income_new`$$ DROP PROCEDURE IF EXISTS `a`$$ CREATE DEFINER=`income_new`@`%` PROCE ...

  8. Json操作(DynamicJson)

    Json的简介 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.它基于ECMAScript的一个子集. JSON采用完全独立于语言的文本格式,但是也使用了 ...

  9. java maven诡异的错误no class found

    从服务器下载一个java web项目,启动老提示no class found,查看maven依赖库,相关的jar包都已经引入.同样一个项目,在别的机器都可以运行,唯独在我本机运行出错. 为了排错,将其 ...

  10. LINUX下WIFI默认连接

    #! /bin/sh ifconfig wlan0 upiwconfig wlan0 key 123456iwconfig wlan0 essid "rat-linux"iwcon ...