CountDownLatch 和 CyclicBarrier

what?

  • CountDownLatch是什么


    CountDownLatch 和 CyclicBarrier_第1张图片
  • CyclicBarrier是什么?

感性认识CountDownLatch

以工人和老板关系为例,老板等待所有工人干完活才开始检查
CountDownLatch示例代码

  • worker代码
package concurrency.in.practice.countdownlatchtest;

import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * Created by haicheng.lhc on 19/07/2017.
 *
 * @author haicheng.lhc
 * @date 2017/07/19
 */
public class Worker implements Runnable {

    private CountDownLatch downLatch;
    private String name;

    public Worker(CountDownLatch downLatch, String name) {
        this.downLatch = downLatch;
        this.name = name;
    }

    public void run() {
        this.doWork();
        try {
            TimeUnit.SECONDS.sleep(new Random().nextInt(10));
        } catch (InterruptedException ie) {
        }
        System.out.println(this.name + "活干完了!");
        this.downLatch.countDown();

    }

    private void doWork() {
        System.out.println(this.name + "正在干活!");
    }
}

  • Boss代码
package concurrency.in.practice.countdownlatchtest;

import java.util.concurrent.CountDownLatch;

/**
 * Created by haicheng.lhc on 19/07/2017.
 *
 * @author haicheng.lhc
 * @date 2017/07/19
 */
public class Boss implements Runnable {

    private CountDownLatch downLatch;

    public Boss(CountDownLatch downLatch) {
        this.downLatch = downLatch;
    }

    public void run() {
        System.out.println("老板正在等所有的工人干完活......");
        try {
            this.downLatch.await();
        } catch (InterruptedException e) {
        }
        System.out.println("工人活都干完了,老板开始检查了!");
    }
}
  • CountDownLatchDemo代码

package concurrency.in.practice.countdownlatchtest;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by haicheng.lhc on 19/07/2017.
 *
 * @author haicheng.lhc
 * @date 2017/07/19
 */
public class CountDownLatchDemo {

    public static void main(String[] args) {
        ExecutorService executor = Executors.newCachedThreadPool();

        CountDownLatch latch = new CountDownLatch(3);

        Worker w1 = new Worker(latch,"张三");
        Worker w2 = new Worker(latch,"李四");
        Worker w3 = new Worker(latch,"王二");

        Boss boss = new Boss(latch);

        executor.execute(w3);
        executor.execute(w2);
        executor.execute(w1);
        executor.execute(boss);

        executor.shutdown();
    }
}

  • 运行结果
CountDownLatch 和 CyclicBarrier_第2张图片

CountDownLatch 使用场景

  • 实现最大的并行性:有时我们想同时启动多个线程,实现最大程度的并行性。例如,我们想测试一个单例类。如果我们创建一个初始计数为1的CountDownLatch,并让所有线程都在这个锁上等待,那么我们可以很轻松地完成测试。我们只需调用 一次countDown()方法就可以让所有的等待线程同时恢复执行。
  • 开始执行前等待n个线程完成各自任务:例如应用程序启动类要确保在处理用户请求前,所有N个外部系统已经启动和运行了。
  • 死锁检测:一个非常方便的使用场景是,你可以使用n个线程访问共享资源,在每次测试阶段的线程数目是不同的,并尝试产生死锁。

感性认识CyclicBarrier

以所有室友都到齐了,每个人才可以点菜为例

  • Roommate代码

package concurrency.in.practice.cyclicbarriertest;

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

/**
 * Created by haicheng.lhc on 19/07/2017.
 *
 * @author haicheng.lhc
 * @date 2017/07/19
 */
public class Roommate implements Runnable {

    private CyclicBarrier barrier;
    private static int Count = 1;
    private int id;

    public Roommate(CyclicBarrier barrier) {
        this.barrier = barrier;
        this.id = Count++;
    }


    @Override
    public void run() {

        System.out.println(id + " : 我到了");
        try {
            //通知barrier,已经完成动作,在等待
            barrier.await();
            System.out.println("Id " + id + " : 点菜吧!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }


    }
}

  • CyclicBarrierDemo代码

package concurrency.in.practice.cyclicbarriertest;

import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by haicheng.lhc on 19/07/2017.
 *
 * @author haicheng.lhc
 * @date 2017/07/19
 */
public class CyclicBarrierDemo {

    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(5, new Runnable() {
            //栅栏动作,在计数器为0的时候执行
            @Override
            public void run() {
                System.out.println("我们都准备好了.");
            }
        });

        ExecutorService es = Executors.newCachedThreadPool();
        for (int i = 0; i < 5; i++) {
            es.execute(new Roommate(barrier));
        }

    }
}

  • 测试结果
CountDownLatch 和 CyclicBarrier_第3张图片

CyclicBarrier使用场景

CyclicBarrier可以用于多线程计算数据,最后合并计算结果的应用场景。比如我们用一个Excel保存了用户所有银行流水,每个Sheet保存一个帐户近一年的每笔银行流水,现在需要统计用户的日均银行流水,先用多线程处理每个sheet里的银行流水,都执行完之后,得到每个sheet的日均银行流水,最后,再用barrierAction用这些线程的计算结果,计算出整个Excel的日均银行流水。

你可能感兴趣的:(CountDownLatch 和 CyclicBarrier)