使用CountDownLatch和CyclicBarrier处理并发线程

闲话不说,首先看一段代码:

{
IValueCallback remoteCallback = new IValueCallback.Stub() {
<strong><span style="color:#ff0000;">(B)</span></strong> public void onReceiveValue(final Bundle value) throws RemoteException {
synchronized (syncObject) {
mReturnValue = arg.result;
syncObject.notify(); //运行完成,notify通知代码继续进行
}
}
};
boolean bSuccess = false;
synchronized (syncObject) {
<strong><span style="color:#ff0000;">(A) </span></strong>sendRequest(CommandConstant.COMMAND_NAVIGATION_ITEM_EXIST, arg, remoteCallback);
try {
syncObject.wait(5000); //等待Callback部分运行完成
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return mReturnValue;
}

来分析一下这段代码的作用: 运行(A)块后,让线程等待——> (B)块返回结果,并通知结束等待——>返回结果值。

抛开可读性不谈。这种处理是能够完毕【同步请求】。But。 来看一下可能有的问题—— 假设IValueCallBack里有两个回调函数,而返回结果取决于两个回调返回的值,那么同步锁要怎么加?怎么notify?

思考了一分钟。还是有些头疼?没关系,以下两位主角CountDownLatch
CyclicBarrier 出场了。

(从未听说过Java这两个类的请举手!我先举为敬……)

先介绍一下CountDownLatch 这个类:

A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

A
CountDownLatch
is initialized with a given count. The
await methods block until the current count reaches zero due to invocations of the
countDown() method, after which all waiting threads are released and any subsequent invocations of
await return immediately. This is a one-shot phenomenon -- the count cannot be reset.

也就是说:能够把它看作一个计数器,仅仅只是这个计数器的操作是原子操作,同一时候仅仅能有一个线程去操作这个计数器,也就是同一时候仅仅能有一个线程去减这个计数器里面的值 (countDown()
方法)。

你能够向CountDownLatch对象设置一个初始的数字作为计数值。不论什么调用这个对象上的await()方法都会堵塞,直到这个计数器的计数值被其它的线程减为0为止。

上面的代码改动为:

{
CountDownLatch cdl = new CountDownLatch (2);//2次的计数器
IValueCallback remoteCallback = new IValueCallback.Stub() {
(B) public void onReceiveValueA(final Bundle value) throws RemoteException {
mReturnValue = arg.result && mReturnValue ;
cdl.countDown(); // 降低一次计数
}
public void onReceiveValueB(final Bundle value) throws RemoteException {
mReturnValue = arg.result&& mReturnValue ;
cdl.countDown(); // 降低一次计数
}
}
};
boolean bSuccess = false;
(A) sendRequest(CommandConstant.COMMAND_NAVIGATION_ITEM_EXIST, arg, remoteCallback);
try {
cdl.await() //等计数器清零后返回结果
} catch (InterruptedException e) {
e.printStackTrace();
}
return mReturnValue;
}

能够看到:回调函数添加成了两个,但CountDownLatch 类轻易的攻克了这个问题,并且避免了显式的使用同步锁。

而这个类真正强大的地方在于。它能够灵活的用于參数传递,去编写很多其它能够解决同步问题的代码。并带来一种比显式同步锁更加清晰的思路。

懂了这个类,CyclicBarrier 也就easy懂了,CyclicBarrier 类使用方法类似,但它用于添加到一个固定值时触发一段操作。

以下用LOL举例,进入英雄联盟这个游戏。须要 A)读进度条 2)10个人都进入后才干開始游戏 3)全部人购买装备 。那么处理同步的方法,能够简单的用这个类写一个Demo。

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class LOLGame {
    public static void main(String[] args) {
     CyclicBarrier cyclicBarrier = new CyclicBarrier(10, new Runnable() {

      @Override
      public void run() {
       System.out.println("欢迎来到召唤师峡谷!");
      }
     });

     for (int i = 0; i < 10; i++) {
      new Thread(new Player(i, cyclicBarrier)).start();
     }
    }

}

class Player implements Runnable {

    private CyclicBarrier cyclicBarrier;
    private int id;

    public Player(int id, CyclicBarrier cyclicBarrier) {
     this.cyclicBarrier = cyclicBarrier;
     this.id = id;
    }

    @Override
    public void run() {
     try {
      System.out.println("玩家" + id + "正在读进度条...");
      cyclicBarrier.await();
      System.out.println("玩家" + id + "购买装备...");
     } catch (InterruptedException e) {
      e.printStackTrace();
     } catch (BrokenBarrierException e) {
      e.printStackTrace();
     }
    }
   }

至于CountDownLatch
的Demo就不再写了,大家能够举一反三,上网搜一下资料。有非常多问题的解都非常精妙。

官方文档中也有一个比較精妙的样例

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html

最后的总结:

1)这两个类是在Java5.0引入的。

2) CountDownLatch 用于逆向计数,CyclicBarrier 用于正向计数,两者都是在计数完毕后通知await()部分继续运行。

3) 粗測之后发现。这两个工具的性能应该是比显式使用同步锁要更高,但我分享这个不仅仅是出于改造代码的目的。

抛开性能不谈,我个人觉得,这两个类最大的意义在于:它们提供了一种用原子计数器解决并发线程问题的思路,将多个线程的同步问题变得很清晰可抽象。

与晦涩的同步锁相比,计数器的实现会更easy将多线程问题抽象,将精力投入到详细逻辑的严谨性,而非投入精力为可能的死锁和性能消耗而头疼。

版权声明:本文博客原创文章。博客,未经同意,不得转载。

时间: 2024-10-13 00:30:59

使用CountDownLatch和CyclicBarrier处理并发线程的相关文章

用CountDownLatch和CyclicBarrier处理并发线程

闲话不说,先来看一段代码: { IValueCallback remoteCallback = new IValueCallback.Stub() { <strong><span style="color:#ff0000;">(B)</span></strong> public void onReceiveValue(final Bundle value) throws RemoteException { synchronized (sy

CountDownLatch 和 CyclicBarrier 的基本使用

CountDownLatch 和 CyclicBarrier 是并发编程中常用的辅助类,两者使用上有点类似,但又有不同. 一.CountDownLatch CountDownLatch 可是实现类似计数器的功能,比如一个线程 A 需要等待其余多个任务执行完毕后才能执行,此时可以使用这个工具类. 构造器: public CountDownLatch(int count) { } 主要方法: public void await() throws InterruptedException { }; /

Java并发编程:CountDownLatch、CyclicBarrier和Semaphore

在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch,CyclicBarrier和Semaphore,今天我们就来学习一下这三个辅助类的用法. 以下是本文目录大纲: 一.CountDownLatch用法 二.CyclicBarrier用法 三.Semaphore用法 若有不正之处请多多谅解,并欢迎批评指正. 请尊重作者劳动成果,转载请标明原文链接: http://www.cnblogs.com/dolphin0520/p/3920397.htm

java并发编程之CountDownLatch与CyclicBarrier

CountDownLatch和CyclicBarrier是jdk concurrent包下非常有用的两个并发工具类,它们提供了一种控制并发流程的手段.本文将会提供一些应用场景,结合源码,对它们的具体实现以及如何使用做一个具体分析. CountDownLatch CountDownLatch允许一个或多个线程等待其他线程完成操作. CountDownLatch使用案例 需求:解析一个文件下多个txt文件数据,可以考虑使用多线程并行解析以提高解析效率.每一个线程解析一个文件里的数据,等到所有数据解析

并发工具类:CountDownLatch、CyclicBarrier、Semaphore

在多线程的场景下,有些并发流程需要人为来控制,在JDK的并发包里提供了几个并发工具类:CountDownLatch.CyclicBarrier.Semaphore. 一.CountDownLatch 1 import java.util.concurrent.CountDownLatch; 2 3 4 public class CountDownLatchTest 5 { //设置N为2 6 static CountDownLatch c = new CountDownLatch(2); 7 p

java并发编程中CountDownLatch和CyclicBarrier的使用

转自:http://blog.csdn.net/hbzyaxiu520/article/details/6183714 在多线程程序设计中,经常会遇到一个线程等待一个或多个线程的场景,遇到这样的场景应该如何解决? 如果是一个线程等待一个线程,则可以通过await()和notify()来实现: 如果是一个线程等待多个线程,则就可以使用CountDownLatch和CyclicBarrier来实现比较好的控制. 下面来详细描述下CountDownLatch的应用场景: 例如:百米赛跑:8名运动员同时

使用Java辅助类(CountDownLatch、CyclicBarrier、Semaphore)并发编程

在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch,CyclicBarrier和Semaphore,今天我们就来学习一下这三个辅助类的用法 一.CountDownLatch用法 CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能.比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了. CountDownLatch类只提

Java并发编程:CountDownLatch、CyclicBarrier和Semaphore (总结)

下面对上面说的三个辅助类进行一个总结: 1)CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同: CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行: 而CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行: 另外,CountDownLatch是不能够重用的,而CyclicBarrier是可以重用的. 2)Semaphore其实和锁有点类似,它一般用于控制对某组资源的访问权

并发编程常用工具类之countDownLatch和cyclicBarrier的使用对比

1.CountDownLatch           countDownLatch的作用是让一组线程等待其他线程完成工作以后在执行,相当于加强版的join(不懂可以百度一下join的用法),一般在初始化的时候会在构造方法传入计数器, 后续,在其他线程中每次调用countDown方法计数器减一,一般在需要等待的线程中调用countDownLatch的await方法阻塞线程,在当计数器为0时,等待线程继续运行. 光看上面的定义描述不是很直观,我们再来结合代码看一下实际运用: 1 public cla