Java中CountDownLatch,CyclicBarrier以及Semaphore的使用场景

时间:2021-07-03 15:19:30

Java并发包中提供了很多有用的工具类来帮助开发者进行并发编程,今天我就来说说CountDownLatch,CyclicBarrier以及Semaphore这三个的用法和使用场景。

1.CountDownLatch使用场景和用法
CountDownLatch一般是用于某个线程等待其他线程执行完之后,它才能执行。例如一家人在等待爸爸妈妈回家,才能进行晚宴,示例代码如下:

public class CountDownLatchTest {

    public static void main(String[] args) throws Exception {
        final CountDownLatch cdl = new CountDownLatch(2);
        new Thread(){
            public void run() {
                try {
                    System.out.println("等待老爸回家...");
                    Thread.sleep(5000);
                    cdl.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                
            };
        }.start();
        
        new Thread(){
            public void run() {
                try {
                    System.out.println("等待老妈回家...");
                    Thread.sleep(5000);
                    cdl.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            };
        }.start();
        
        cdl.await();
        System.out.println("老爸老妈回来了...");
        System.out.println("晚宴开始了...");
    }

}


2.CyclicBarrier(栅栏)使用场景和用法
CyclicBarrier一般是一组线程等待至某个状态,然后这一组线程才能同时执行(感觉跟CountDownLatch有点类似啊,不过仔细想想还是有差别的,感觉容易混淆)。
代码示例如下:

public class CyclicBarrierTest {

    public static void main(String[] args) {
        int count = 3;
        CyclicBarrier cb = new CyclicBarrier(count, new Runnable() {
            @Override
            public void run() {
                //此处所有线程都调用了await方法之后,会走到这里
                System.out.println("所有线程操作完成之后都调用了await方法");
            }
        });
        
        for(int i=0;i<count;i++){
            new WriteLogHandler(cb).start();
        }
    }
    
    static class WriteLogHandler extends Thread{
        
        private CyclicBarrier cb = null;
        
        public WriteLogHandler(CyclicBarrier cb) {
            this.cb = cb;
        }
        
        @Override
        public void run() {
            try {
                System.out.println("线程:" + Thread.currentThread().getName() + "开始写日志");
                Thread.sleep(2000);
                System.out.println("线程:" + Thread.currentThread().getName() + "写日志结束,等待其他线程");
                cb.await();
                
                System.out.println("所有线程写日志数据结束,继续其他操作");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

3.Semaphore(信号量)使用场景和用法

Semaphore类似锁的用法,用于控制对某资源的访问权限,示例代码如下:

public class SemaphoreTest {

    public static void main(String[] args) {
        ExecutorService executor = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(5);
        
        for(int i=0;i<10;i++){
            final int num = i;
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        semaphore.acquire();
                        System.out.println("正在执行任务" + num);
                        Thread.sleep((long)Math.random() * 1000);
                        System.out.println("任务" + num + "执行结束");
                        semaphore.release();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        executor.shutdown();
    }

}

以上就是这三个并发工具类的使用场景和示例,欢迎大家一起交流。