Java并发编程的艺术(九)——闭锁、同步屏障和信号量

闭锁:CountDownLatch

使用场景

当前线程需要等待若干条线程执行完毕后,才能继续执行的情况。

也可以是若干个步骤执行完毕后的情况。

使用方法

初始化闭锁的时候,填入计数值,然后等待其他线程或者步骤对计数值进行操作减减。当计数值变为0的时候,线程就会从闭锁的await()方法处继续执行。

不能将计数值的参数设置为0,因为这样就毫无意义。

使用示例

// 初始化闭锁,并设置资源个数
CountDownLatch c = new CountDownLatch(2);

Thread t1 = new Thread( new Runnable(){
    public void run(){
        // 加载资源1
        loadSomething();
        // 本资源加载完后,计数值-1
        c.countDown();
    }
} ).start();

Thread t2 = new Thread( new Runnable(){
    public void run(){
        // 加载资源2
        loadSomething();
        // 本资源加载完后,计数值-1
        c.countDown();
    }
} ).start();

Thread t3 = new Thread( new Runnable(){
    public void run(){
        // 线程阻塞,等待计数值为0
        c.await();
        // 当闭锁计数值为0时,await返回,执行接下来的任务
        dosomething();
    }
} ).start();

同步屏障:CyclicBarrier

作用

让一组线程中的每一个线程达到一个位置的时候被阻塞,直到最后一个线程到达屏障,所有被阻塞的线程继续运行。

与闭锁的区别

  • 闭锁只能阻塞一个线程,目的是为了让当个线程满足某种条件。
  • 同步屏障可以满足多个线程同时阻塞,并同时继续执行。

使用方法

在实例化同步屏障的时候,填入线程等待个数,当等待的线程数满足这个数值要求,同步屏障才会释放。

使用示例

// 实例化对象,填入需要等待的线程数和屏障开启的任务
CyclicBarrier barrier = new CyclicBarrier(10, new Runnable(){
    public void run(){
        //当所有线程准备完毕后触发此任务
    }
});

// 启动10条线程
for( int i=0; i < 10; i++ ) {
    new Thread( new Runnable() {
        public void run() {
            // 等待,(同步屏障数量-1,直到为0时,打开屏障)
            barrier.await();

            dosomething();
        }
    } ).start();
}

信号量:

作用

可以控制访问特定资源的线程数量。

使用方法

示例化对象的时候,填入最大可访问的线程数量。在获取资源之前,调用acquire,获取完毕之后,调用release。

使用示例

// 实例化信号量对象,设置最大访问线程参数为5
Semaphore semaphore = new Semaphore(5);

// 启动 10条线程
for ( int i=0; i < 10; i++ ) {
    new Thread( new Runnbale(){
        public void run(){
            // 获取资源,若此时资源数值为0,则阻塞,当资源数大于0,则继续执行
            semaphore.acquire();
            // 任务代码
            soSomething();
            // 释放资源
            semaphore.release();
        }
    } ).start();
}
原文地址:https://www.cnblogs.com/lippon/p/14117661.html