• 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();
                }
            }
        }
    
    }
    
    
    
    

    运行结果

  • 相关阅读:
    仿照everything写的一个超级速查 原创
    [转]SharePoint 2013 Online App Development – Part 1
    [转]SharePoint 2013 App 开发 (2)
    [转]ASP.NET自定义控件复杂属性声明持久性浅析
    HasRights方法参数
    故障分析神器——BTrace
    JVM——Memory Analyzor分析内存溢出
    关于句柄
    Java内存区域与内存溢出
    命令行的使用
  • 原文地址:https://www.cnblogs.com/fonxian/p/10872841.html
Copyright © 2020-2023  润新知