并发工具

并发工具

CountDownLatch(倒计时器)

背景

  • 1.5之后被引入的,跟它一起被引入的工具还有CyclicBarrier、Semaphore、concurrentHashMap和BlockingQueue。
  • 存在于java.util.current包下

概念

  • countDownLatch这个类使用一个线程等待其他线程各自执行完成后再执行
  • 是通过计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后计数器就减1,当计数器为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了。

适用于一个线程需要等待其他多个线程执行结果的应用场景

进程,线程,协程
实现代码


public class CountdownLatchExample {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        final int totalThread = 10;
        CountDownLatch countDownLatch = new CountDownLatch(totalThread);
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.execute(() -> {
    
    
            int count = totalThread;
            while (count > 0) {
    
    
                try {
    
    
                    Thread.sleep(2000);
                    countDownLatch.countDown();
                    // 每个线程在这里将countDownLatch减少
                    System.out.println("run...    " + count--);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
        });
        System.out.println("I`m waiting~~");
        // 这个主线程在这里等待其他线程把countDownLatch的值减为0,再继续往下执行。
        countDownLatch.await();
        System.out.println("end..");
        executorService.shutdown();
    }
}

result:
在这里插入图片描述

CyclicBarrier

概念:

循环栅栏。可以循环利用的屏障,让所有线程都等待完成后才继续下一步行动
例子:就像生活中我们会约朋友们到某个餐厅一起吃饭,有些朋友可能会早到,有些朋友可能会晚到,但是这个餐厅规定必须等到所有人到齐之后才会让我们进去。这里的朋友们就是各个线程,餐厅就是 CyclicBarrier。

使用场景:

可以用于多线程计算数据,最后合并计算结果的场景
代码实现(栅栏可以重复利用)

package Interview.多线程.CountDownLatch;

import java.util.concurrent.CyclicBarrier;

/**
 * @author chenbin
 * @datetime 2020-08-28 11:44
 */

public class CyclicBarrierDemo {
    
    

    static class TaskThread extends Thread {
    
    

        CyclicBarrier barrier;

        public TaskThread(CyclicBarrier barrier) {
    
    
            this.barrier = barrier;
        }

        @Override
        public void run() {
    
    
            try {
    
    
                Thread.sleep(1000);
                System.out.println(getName() + " 到达栅栏 A");
                barrier.await();
                System.out.println(getName() + " 冲破栅栏 A");

                Thread.sleep(2000);
                System.out.println(getName() + " 到达栅栏 B");
                barrier.await();
                System.out.println(getName() + " 冲破栅栏 B");
            } catch (Exception e) {
    
    
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
    
    
        int threadNum = 5;
        CyclicBarrier barrier = new CyclicBarrier(threadNum, new Runnable() {
    
    

            @Override
            public void run() {
    
    
                System.out.println(Thread.currentThread().getName() + " 完成最后任务");
            }
        });

        for(int i = 0; i < threadNum; i++) {
    
    
            new TaskThread(barrier).start();
        }
    }

}

result
在这里插入图片描述

CountDownLatch和CyclicBarrier的比较

  • CountDownLatch 是一次性的,CyclicBarrier 是可以循环利用的
  • CountDownLatch 参与的线程的职责不一样的,有的在倒计时,有的在等待倒计时结束。CyclicBarrier 参与的线程池职责是一样的。
  • CyclicBarrier会在await处阻塞等待,而CountDownLatch在await处不会阻塞等待
  • CyclicBarrier提供了例如isBroken,getNumberWaiting等方法能够查询当前状态,而CountDownLatch提供的方法较少

Semaphore

概念

Semaphore是一个信号量,必须由获取它的线程释放。
常用于限制可以访问某些资源的线程数量,例如通过Semaphore限流。

适用于对特定资源需要控制能够并发访问资源的线程个数。需要先执行acquire方法获取许可证后线程才能往下继续执行,否则只能阻塞等待,使用完后需要用release方法归还许可

代码实现


public class SemaphoreExample {
    
    
    public static void main(String[] args) {
    
    
        final int clientCount = 3;
        final int totalRequestCount = 10;
        Semaphore semaphore = new Semaphore(clientCount);
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < totalRequestCount; i++) {
    
    
            executorService.execute(() ->{
    
    
                try{
    
    
                    semaphore.acquire();
                    System.out.println(semaphore.availablePermits()+" ");
                }catch (Exception e){
    
    
                    e.printStackTrace();
                }finally {
    
    
                    semaphore.release();
                }
            });
        }
        executorService.shutdown();
    }
}

result
在这里插入图片描述
阻塞在线程内部,同时执行的线程数量不会超过3

猜你喜欢

转载自blog.csdn.net/weixin_42061487/article/details/108276401