Phaser由java7中推出,是Java SE 7中新增的一个使用同步工具,在功能上面它与CyclicBarrier、CountDownLatch有些重叠,但是它提供了更加灵活、强大的用法。

CyclicBarrier,允许一组线程互相等待,直到到达某个公共屏障点。它提供的await()可以实现让所有参与者在临界点到来之前一直处于等待状态。

CountDownLatch,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。它提供了await()、countDown()两个方法来进行操作。

在Phaser中,它把多个线程协作执行的任务划分为多个阶段,编程时需要明确各个阶段的任务,每个阶段都可以有任意个参与者,线程都可以随时注册并参与到某个阶段。

构造

Phaser创建后,初始阶段编号为0,构造函数中指定初始参与个数。

注册:Registration

Phaser支持通过register()和bulkRegister(int parties)方法来动态调整注册任务的数量。

Arrival

每个Phaser实例都会维护一个phase number,初始值为0。每当所有注册的任务都到达Phaser时,phase number累加,并在超过Integer.MAX_VALUE后清零。arrive()和arriveAndDeregister()方法用于记录到达;其中arrive(),某个参与者完成任务后调用;arriveAndDeregister(),任务完成,取消自己的注册。arriveAndAwaitAdvance(),自己完成等待其他参与者完成,进入阻塞,直到Phaser成功进入下个阶段。

example 1

public class PhaserTest_1 {
public static void main(String[] args) {
Phaser phaser = new Phaser(5); for(int i = 0 ; i < 5 ; i++){
Task_01 task_01 = new Task_01(phaser);
Thread thread = new Thread(task_01, "PhaseTest_" + i);
thread.start();
}
} static class Task_01 implements Runnable{
private final Phaser phaser; public Task_01(Phaser phaser){
this.phaser = phaser;
} @Override
public void run() {
System.out.println(Thread.currentThread().getName() + "执行任务完成,等待其他任务执行......");
//等待其他任务执行完成
phaser.arriveAndAwaitAdvance();
System.out.println(Thread.currentThread().getName() + "继续执行任务...");
}
}
}

运行结果:

PhaseTest_0执行任务完成,等待其他任务执行......
PhaseTest_1执行任务完成,等待其他任务执行......
PhaseTest_3执行任务完成,等待其他任务执行......
PhaseTest_2执行任务完成,等待其他任务执行......
PhaseTest_4执行任务完成,等待其他任务执行......
PhaseTest_4继续执行任务...
PhaseTest_1继续执行任务...
PhaseTest_0继续执行任务...
PhaseTest_2继续执行任务...
PhaseTest_3继续执行任务...

在该实例中我们可以确认,所有子线程的****+”继续执行任务…”,都是在线程调用arriveAndAwaitAdvance()方法之后执行的。

example 2

前面提到过,Phaser提供了比CountDownLatch、CyclicBarrier更加强大、灵活的功能,从某种程度上来说,Phaser可以替换他们:

public class PhaserTest_5 {
public static void main(String[] args) {
Phaser phaser = new Phaser(1); //相当于CountDownLatch(1) //五个子任务
for(int i = 0 ; i < 3 ; i++){
Task_05 task = new Task_05(phaser);
Thread thread = new Thread(task,"PhaseTest_" + i);
thread.start();
} try {
//等待3秒
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
phaser.arrive(); //countDownLatch.countDown()
} static class Task_05 implements Runnable{
private final Phaser phaser; Task_05(Phaser phaser){
this.phaser = phaser;
} @Override
public void run() {
phaser.awaitAdvance(phaser.getPhase()); //countDownLatch.await()
System.out.println(Thread.currentThread().getName() + "执行任务...");
}
}
}

在这里,任务一开始并没有真正执行,而是等待三秒后执行。

对于CyclicBarrier就更加简单了,直接arriveAndAwaitAdvance()方法替换,如example 1。

example 3

在CyclicBarrier中当任务执行完之后可以执行一个action,在Phaser中同样有一个对应的action,只不过Phaser需要重写onAdvance()方法:

public class PhaserTest_3 {
public static void main(String[] args) {
Phaser phaser = new Phaser(3){
/**
* registeredParties:线程注册的数量
* phase:进入该方法的线程数,
*/
protected boolean onAdvance(int phase, int registeredParties) {
System.out.println("执行onAdvance方法.....;phase:" + phase + "registeredParties=" + registeredParties);
return phase == 3;
}
}; for(int i = 0 ; i < 3 ; i++){
Task_03 task = new Task_03(phaser);
Thread thread = new Thread(task,"task_" + i);
thread.start();
}
while(!phaser.isTerminated()){
phaser.arriveAndAwaitAdvance(); //主线程一直等待
}
System.out.println("主线程任务已经结束....");
} static class Task_03 implements Runnable{
private final Phaser phaser; public Task_03(Phaser phaser){
this.phaser = phaser;
} @Override
public void run() {
do{
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "开始执行任务...");
phaser.arriveAndAwaitAdvance();
}while(!phaser.isTerminated());
}
}
}

运行结果:

task_0开始执行任务...
task_1开始执行任务...
task_1执行onAdvance方法.....;phase:0registeredParties=3
task_2开始执行任务...
task_0开始执行任务...
task_1开始执行任务...
task_0执行onAdvance方法.....;phase:1registeredParties=3
task_2开始执行任务...
task_2执行onAdvance方法.....;phase:2registeredParties=3
主线程任务已经结束....
task_0开始执行任务...

 

参考博文:

1、What's New on Java 7 Phaser

2、http://blog.csdn.net/andycpp/article/details/8838820

【Java并发编程实战】-----“J.U.C”:Phaser的更多相关文章

  1. 【Java并发编程实战】-----“J.U.C”:CountDownlatch

    上篇博文([Java并发编程实战]-----"J.U.C":CyclicBarrier)LZ介绍了CyclicBarrier.CyclicBarrier所描述的是"允许一 ...

  2. 【Java并发编程实战】-----“J.U.C”:CyclicBarrier

    在上篇博客([Java并发编程实战]-----"J.U.C":Semaphore)中,LZ介绍了Semaphore,下面LZ介绍CyclicBarrier.在JDK API中是这么 ...

  3. 【Java并发编程实战】-----“J.U.C”:ReentrantReadWriteLock

    ReentrantLock实现了标准的互斥操作,也就是说在某一时刻只有有一个线程持有锁.ReentrantLock采用这种独占的保守锁直接,在一定程度上减低了吞吐量.在这种情况下任何的"读/ ...

  4. 【Java并发编程实战】-----“J.U.C”:Semaphore

    信号量Semaphore是一个控制访问多个共享资源的计数器,它本质上是一个"共享锁". Java并发提供了两种加锁模式:共享锁和独占锁.前面LZ介绍的ReentrantLock就是 ...

  5. 【Java并发编程实战】-----“J.U.C”:ReentrantLock之三unlock方法分析

    前篇博客LZ已经分析了ReentrantLock的lock()实现过程,我们了解到lock实现机制有公平锁和非公平锁,两者的主要区别在于公平锁要按照CLH队列等待获取锁,而非公平锁无视CLH队列直接获 ...

  6. 【Java并发编程实战】-----“J.U.C”:ReentrantLock之一简介

    注:由于要介绍ReentrantLock的东西太多了,免得各位客官看累,所以分三篇博客来阐述.本篇博客介绍ReentrantLock基本内容,后两篇博客从源码级别分别阐述ReentrantLock的l ...

  7. 【Java并发编程实战】----- AQS(四):CLH同步队列

    在[Java并发编程实战]-–"J.U.C":CLH队列锁提过,AQS里面的CLH队列是CLH同步锁的一种变形.其主要从两方面进行了改造:节点的结构与节点等待机制.在结构上引入了头 ...

  8. 【Java并发编程实战】----- AQS(二):获取锁、释放锁

    上篇博客稍微介绍了一下AQS,下面我们来关注下AQS的所获取和锁释放. AQS锁获取 AQS包含如下几个方法: acquire(int arg):以独占模式获取对象,忽略中断. acquireInte ...

  9. 【Java并发编程实战】—– AQS(四):CLH同步队列

    在[Java并发编程实战]-–"J.U.C":CLH队列锁提过,AQS里面的CLH队列是CLH同步锁的一种变形. 其主要从双方面进行了改造:节点的结构与节点等待机制.在结构上引入了 ...

  10. Java并发编程实战 02Java如何解决可见性和有序性问题

    摘要 在上一篇文章当中,讲到了CPU缓存导致可见性.线程切换导致了原子性.编译优化导致了有序性问题.那么这篇文章就先解决其中的可见性和有序性问题,引出了今天的主角:Java内存模型(面试并发的时候会经 ...

随机推荐

  1. Partition:增加分区

    在关系型 DB中,分区表经常使用DateKey(int 数据类型)作为Partition Column,每个月的数据填充到同一个Partition中,由于在Fore-End呈现的报表大多数是基于Mon ...

  2. logstash file输入,无输出原因与解决办法

    1.现象 很多同学在用logstash input 为file的时候,经常会出现如下问题:配置文件无误,logstash有时一直停留在等待输入的界面 2.解释 logstash作为日志分析的管道,在实 ...

  3. X86和X86_64和X64有什么区别?

    x86是指intel的开发的一种32位指令集,从386开始时代开始的,一直沿用至今,是一种cisc指令集,所有intel早期的cpu,amd早期的cpu都支持这种指令集,ntel官方文档里面称为&qu ...

  4. Jquery的事件操作和文档操作

    对于熟悉前端开发的小伙伴,相信对于Jquery一定不陌生,相对于JavaScript的繁琐,Jquery更加的简洁,当然简洁不意味着简单,我们可以使用Jquery完成我们想要实现全部功能,这里为小白们 ...

  5. 零OCR基础6行代码实现C#验证码识别

    这两天因为工作需要,要到某个网站采集信息,一是要模拟登陆,二是要破解验证码,本想用第三方付费打码,但是想想网上免费的代码也挺多的,于是乎准备从网上撸点代码下来,谁知道,撸了好多个都不行,本人以前也没接 ...

  6. 流程开发Activiti 与SpringMVC整合实例

    流程(Activiti) 流程是完成一系列有序动作的概述.每一个节点动作的结果将对后面的具体操作步骤产生影响.信息化系统中流程的功能完全等同于纸上办公的层级审批,尤其在oa系统中各类电子流提现较为明显 ...

  7. Java进击C#——前言

    本章简言 记得三年前笔者来到现在的公司的时候,公司人口不出十个人.那个时候笔者刚从日本回来,想在福州.厦门.青岛找一个合适自己发展的机会.最后我的一个福州的朋友打电话希望我能过去帮他,跟他一起创业.这 ...

  8. 【搬砖】安卓入门(1)- Java开发入门

    01.01_计算机基础知识(计算机概述)(了解) A:什么是计算机?计算机在生活中的应用举例 计算机(Computer)全称:电子计算机,俗称电脑.是一种能够按照程序运行,自动.高速处理海量数据的现代 ...

  9. android手机登录时遇到“QQ安全登录发现病毒”解决

    android手机作为开源系统非常容易感染病毒,有时候我们会经常遇到手机QQ登录时检测到app被感染,一般情况是由手机感染病毒所引起的,安装腾讯管家后只能检测病毒和卸载感染病毒的软件,不能清除病毒.解 ...

  10. 两个变量交换的四种方法(Java)

    对于两种变量的交换,我发现四种方法,下面我用Java来演示一下. 1.利用第三个变量交换数值,简单的方法. (代码演示一下) class TestEV //创建一个类 { public static ...