并发工具类:CountDownLatch、CyclicBarrier、Semaphore

在多线程的场景下,有些并发流程需要人为来控制,在JDK的并发包里提供了几个并发工具类:CountDownLatch、CyclicBarrier、Semaphore。

一、CountDownLatch

这个CountDownLatch的构造函数接受一个int类型的参数作为计数器,N表示阻塞的线程必须等待N次countDown才能执行

每次调用CountDownLatch的countDown方法时,N就会减1,而这个方法可以使用到任何地方,这里的N点可以是N个线程,也可以是一个线程的N个步骤

而CountDownLatch的await方法则会阻塞当前线程,直到N为0的时候才能执行。

线程的join方法,这个方法也是可以阻塞当前线程,等待某线程执行完成,通过对比,我们可以发现使用CountDownLatch这个工具类更灵活,因为countDown可以用

在任何线程的任何地方。

CountDownLatch适合一个大任务拆分成多个小任务,然后再所有子任务完成后,通知其他的后续操作开始执行

二、同步屏障CyclicBarrier

CyclicBarrier默认的构造方法CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达屏障,然后当前线程被阻塞,直到被拦截的线程全部都到达了屏障,然后前边被阻塞的线程才能开始执行,否则会被一直阻塞。

CyclicBarrier可以用于多线程计算数据,最后合并结果的场景;由于CyclicBarrier的计数器可以重置,所以可以使用它处理更为复杂的业务场景,而CountDownLatch计数器只能使用一次。

三、信号量Semaphore

无论是内部锁sychronized还是重入锁ReentrantLock,一次都只允许一个线程访问某一个资源,而信号量却可以指定多个线程同时方位某一个资源主要用来控制同时访问特定资源的线程数量,它通过协议各个线程,以保证合理的使用公告资源

import java.util.concurrent.Semaphore;

public class SemaphoreTest implements Runnable{

    final Semaphore s = new Semaphore(5);
    
    @Override
    public void run() {
        try {
            s.acquire();
            Thread.sleep(500);
            System.out.println(Thread.currentThread().getName()+" is Done!");
            s.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

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

public class MainTest {

    public static void main(String[] args) {
        SemaphoreTest s = new SemaphoreTest();
        ExecutorService threadPool = Executors.newFixedThreadPool(20);
        for(int i  = 0; i < 20; i++) {
            threadPool.submit(s);
        }
        threadPool.shutdown();
    }

}

执行的结果是每五个线程为一组打印消息。

线程池里面有20个可重复使用的线程数量,但是信号量只有5个,也就是每次只能并发5个线程执行,其他线程阻塞。

信号量为5,可以认为线程池里有5把锁,每个线程调用acquire和release分别表示获取锁和释放锁,这样,通过信号量就可以调度多个线程的执行

原文地址:https://www.cnblogs.com/cherish010/p/8514657.html