Java并发编程读书笔记——CountDownLatch、CyclicBarrier、Semaphore

一、CountDownLatch:

        CountDownLatch允许一个或者多个线程等待其他线程完成操作。

        假设现在需要解析一个Excel里的多个sheet数据,此时可以使用多线程。等到所有sheet都解析完成后,需要提示解析完成。最简单的方法是使用join()方法:

public class JoinCountDownLatchTest {
    public static void main(String[] args) throws InterruptedException {
        Thread parser1 = new Thread(new Runnable() {
            @Override
            public void run() {

            }
        });

        Thread parser2 = new Thread(new Runnable() {
            @Override
            public void run() {

            }
        });

        parser1.start();
        parser2.start();
        parser1.join();
        parser2.join();
        System.out.println("all parser finish!");
    }
}

join用于让当前线程等待join线程结束。其原理是不停检查join线程是否存活,如果join线程存活,则让当前线程永远等待。

JDK1.5之后的并发包中提供的CountDownLatch也可以实现join的功能,并且比join的功能更多。

public class CountDownLatchTest {
    static CountDownLatch c = new CountDownLatch(2);  //N
    public static void main(String[] args) throws InterruptedException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(1);
                c.countDown();  //countDown()每调用一次,N-1
                System.out.println(2);
                c.countDown();
            }
        }).start();
        c.await();   //阻塞当前线程,直到N变为0
        System.out.println(3);
    }
}

由于countDown方法可以用在任何地方,所以这里的N个点,可以是N个线程,即一个线程里的N个执行步骤。用在多线程时,只需要把这个CountDownLatch的引用传递到线程里即可。

注意:CountDownLatch不可能重新初始化或者修改CountDownLatch对象的内部计数器的值。

二、CyclicBarrier(回环栅栏)

        字面意思是可循环使用的屏障。他要做的事情是,让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障时,平藏才会开门,所有被屏障拦截的线程才会继续运行。

import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierTest {
    static CyclicBarrier c = new CyclicBarrier(2);  //拦截2个线程
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("线程1将到达屏障");
                    c.await();  //提示当前线程到达屏障
                    System.out.println("线程1继续运行...");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();

        try {
            System.out.println("主线程将要到达屏障...");
            c.await();
            System.out.println("主线程继续执行...");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

运行结果:


CyclicBarrier还提供了一个更高级的构造函数CyclicBarrier(int parties,Runnable barrierAction):用于在线程达到屏障时,优先执行barrierAction。

应用场景:可用于多线程的计算数据,最后合并计算结果的场景。

CyclicBarrier和CountDownLatch的区别:CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset()方法重置,所以CyclicBarrier能处理更为复杂的业务场景,例如计算发生错误,可以重置计数器。

三、Semaphore(信号量)

        是用来控制同时访问特定资源的线程数量。例如XX马路要限制流量,只允许同时有100辆车在这条路上行驶,其他的必须在路口等待。当100辆中有5辆驶出这条马路,就可以让另外5辆驶入这条马路。

        应用场景:Semaphore可以做流量控制,特别是公用资源有限的应用场景,比如数据库连接。

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

public class SemaphoreTest {
    private static final int THREAD_COUNT = 30;
    private static ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_COUNT);
    private static Semaphore s = new Semaphore(10); //最大流量为10
    public static void main(String[] args) {
        for(int i=0;i<THREAD_COUNT;i++){
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        s.acquire();    //获取一个许可证
                        System.out.println("save data ok!");
                        s.release();    //归还许可证
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        threadPool.shutdown();
    }
}
代码中,虽然有30个线程在执行,但是只允许10个并发执行。

猜你喜欢

转载自blog.csdn.net/crazer_cy/article/details/79750085
今日推荐