Java并发编程(三) —— CountDownLatch、Semaphore、CyclicBarrier

一、CountDownLatch

文档描述

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

是一个同步帮助工具,允许一个或多个线程等待一系列其他线程操作完后,再执行。

count down 倒计时

latch 插锁

在Java中Latch结尾的也叫 闭锁

用法

方法名 作用
await() 线程会被挂起,它会等待直到count值为0才继续执行

简单示例


public class CountDownLatchDemo {

    private static final ExecutorService threadPool = new ThreadPoolExecutor(50, 100,
            5, TimeUnit.SECONDS,
            new SynchronousQueue<>(),
            new BasicThreadFactory.Builder().namingPattern("thread-%d").build());

    public static void main(String[] args) throws InterruptedException {

        CountDownLatch countDownLatch = new CountDownLatch(10);
        for (int i = 1; i <= 10; i++) {
            threadPool.execute(() -> {
                System.out.println("test-"+new Random().nextInt());
                countDownLatch.countDown();
            });
        }

        countDownLatch.await();
        System.out.println("end");
        threadPool.shutdown();

    }

}


应用场景

同事A需要执行任务A,进行A类数据的收集
同事B需要执行任务B,进行B类数据的收集
项目经理需要等到A和B的数据都收集齐之后,进行统计,然后向上汇报。

public class CountDownLatchDemo2 {

    private static final ExecutorService threadPool = new ThreadPoolExecutor(50, 100,
            5, TimeUnit.SECONDS,
            new SynchronousQueue<>(),
            new BasicThreadFactory.Builder().namingPattern("thread-%d").build());


    public static void main(String[] args) {

        CountDownLatch countDownLatch = new CountDownLatch(2);
        // 收集数据A
        threadPool.execute(new TaskA(countDownLatch));
        // 收集数据B
        threadPool.execute(new TaskB(countDownLatch));
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 进行统计工作
        System.out.println("进行统计工作");
        // 向上汇报
        System.out.println("向上汇报");
        System.out.println("任务结束");
        threadPool.shutdown();
    }

    static class TaskA implements Runnable {

        private CountDownLatch countDownLatch;

        public TaskA(CountDownLatch countDownLatch) {
            this.countDownLatch = countDownLatch;
        }

        @Override
        public void run() {

            try {
                System.out.println("执行任务A-----------");
                TimeUnit.SECONDS.sleep(5);
                System.out.println("执行任务A完成");
                countDownLatch.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    static class TaskB implements Runnable {

        private CountDownLatch countDownLatch;

        public TaskB(CountDownLatch countDownLatch) {
            this.countDownLatch = countDownLatch;
        }

        @Override
        public void run() {

            try {
                System.out.println("执行任务B-----------");
                TimeUnit.SECONDS.sleep(7);
                System.out.println("执行任务B完成");
                countDownLatch.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


}


运行结果

二、Semaphore

文档描述

A counting semaphore.  Conceptually, a semaphore maintains a set of* permits.  Each {@link #acquire} blocks if necessary until a permit is* available, and then takes it.  Each {@link #release} adds a permit,* potentially releasing a blocking acquirer.* However, no actual permit objects are used; the {@code Semaphore} just* keeps a count of the number available and acts accordingly.**

Semaphores are often used to restrict the number of threads than can* access some (physical or logical) resource. For example, here is* a class that uses a semaphore to control access to a pool of items:

用于控制并发量。

用法

方法名 作用
acquire() 从该信号量获取一个许可,在获取许可前线程将一直阻塞
release() 释放一个许可,将其返回给信号量

简单示例


public class SemaphoreDemo {

    private static final ExecutorService threadPool = new ThreadPoolExecutor(20, 100,
            1, TimeUnit.MINUTES,
            new SynchronousQueue<>(),
            new BasicThreadFactory.Builder().namingPattern("thread-%d").build());

    private static volatile int count = 0;

    public static void main(String[] args) {

        Semaphore semaphore = new Semaphore(3);

        for (int i = 0; i < 100; i++) {
            threadPool.execute(() -> {
                try {
                    semaphore.acquire();
                    System.out.println("test--" + count);
                    try {
                        TimeUnit.SECONDS.sleep(3);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    count++;
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            });
        }

    }

}



应用场景

公司有100个人需要体检,医院每次最多只能体检3人。

当有3个人在体检时,其他人只能等待,有1个人体检完,下一个人可以补上。

public class SemaphoreDemo {

    private static final ExecutorService threadPool = new ThreadPoolExecutor(20, 100,
            1, TimeUnit.MINUTES,
            new SynchronousQueue<>(),
            new BasicThreadFactory.Builder().namingPattern("thread-%d").build());

    private static volatile int count = 0;

    public static void main(String[] args) {

        Semaphore semaphore = new Semaphore(3);

        for (int i = 0; i < 100; i++) {
            threadPool.execute(() -> {
                try {

                    String id = new Random().nextInt() + "";
                    semaphore.acquire();
                    System.out.println("同事ID:" + id + ",开始体检");
                    try {
                        TimeUnit.SECONDS.sleep(3L);
                        TimeUnit.MILLISECONDS.sleep(new Random(10000).nextInt());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("同事ID:" + id + ",体检结束" + count);
                    count++;
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            });
        }

    }

}


运行结果

三、CyclicBarrier

概念

和闭锁不同的是,栅栏是用来等待线程的,闭锁是用来等待时间。

当指定线程数都到达某个点,才开始执行后续的操作。

就好比有10个人赛跑,要跑400米,在100米设置一个栅栏,当这10个人都到达了这个栅栏的时候,才取消栅栏,全部放行。

简单示例

public class CyclicBarrierDemo {

    private static final ExecutorService threadPool = new ThreadPoolExecutor(50, 100,
            1, TimeUnit.MINUTES,
            new SynchronousQueue<>(),
            new BasicThreadFactory.Builder().namingPattern("thread-%d").build());

    public static void main(String[] args) {

        CyclicBarrier cyclicBarrier = new CyclicBarrier(10);
        for (int i = 0; i < 10; i++) {
            threadPool.execute(() -> {
                System.out.println("线程" + Thread.currentThread().getId() + "跑到100米,遇到栅栏,停下");
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
                System.out.println("继续跑完剩下300米");
            });
        }

        threadPool.shutdown();

    }

}


应用场景

还用上面CountDownLatch的例子,

同事A需要执行任务A,进行A类数据的收集
同事B需要执行任务B,进行B类数据的收集
项目经理需要等到A和B的数据都收集齐之后,进行统计,然后向上汇报。


public class CyclicBarrierDemo2 {

    private static final ExecutorService threadPool = new ThreadPoolExecutor(50, 100,
            5, TimeUnit.SECONDS,
            new SynchronousQueue<>(),
            new BasicThreadFactory.Builder().namingPattern("thread-%d").build());

    private static volatile boolean flag = false;

    public static void main(String[] args) {

        CyclicBarrier cb = new CyclicBarrier(2);
        // 收集数据A
        threadPool.execute(new TaskA(cb));
        // 收集数据B
        threadPool.execute(new TaskB(cb));
        threadPool.shutdown();
    }

    static class TaskA implements Runnable {

        private CyclicBarrier cb;

        public TaskA(CyclicBarrier cb) {
            this.cb = cb;
        }

        @Override
        public void run() {

            try {
                System.out.println("执行任务A-----------");
                TimeUnit.SECONDS.sleep(5);
                System.out.println("执行任务A完成");
                cb.await();
                if(!flag){
                    flag = true;
                    System.out.println("进行统计工作");
                    System.out.println("向上汇报");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }

    static class TaskB implements Runnable {

        private CyclicBarrier cb;

        public TaskB(CyclicBarrier cb) {
            this.cb = cb;
        }

        @Override
        public void run() {

            try {
                System.out.println("执行任务B-----------");
                TimeUnit.SECONDS.sleep(7);
                System.out.println("执行任务B完成");
                cb.await();
                if(!flag){
                    flag = true;
                    System.out.println("进行统计工作");
                    System.out.println("向上汇报");
                    System.out.println("任务结束");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }

}



运行结果

posted @ 2019-05-15 23:09  清泉白石  阅读(188)  评论(0编辑  收藏  举报