Java并发编程—并发工具类

并发编程—并发工具类

这里将会记录一些并发工具类:CountDownLatch、CyclicBarrier、Semaphore

CountDownLatch

CountDownLatch是什么

CountDownLatch是在java1.5被引入的,存在于java.util.concurrent包下。它的作用是当一个线程任务完成后,它必须等待其它的线程的任务执行完成后,主线程才能继续往下执行。
CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1(这个可以根据业务去确定,也就是不一定就是减1)。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。
在这里插入图片描述

CountDownLatch如何使用

方法说明:

  • new CountDownLatch(6):我们实例化CountDownLatch时,需要传入一个参数[int]count,这个count就是计数器的数值。
  • countDown():做减一的操作,每调用一次,计数器的数值就会减1。
  • await():使线程阻塞,等待计数器的数值变成0时,放行阻塞的线程。

具体使用:

    /**
     * 定义
     */
    private static CountDownLatch downLatch = new CountDownLatch(6);
    /**
     * 扣减的线程
     */
    static class DownLatchThread implements Runnable {

        @Override
        public void run() {
        	// 业务代码
         
            // countDown 可以理解为扣减1也就是 -1
            downLatch.countDown();
            System.out.println("Thread: " + Thread.currentThread().getId());
        }
    }

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 6; i++) {
            // 启动六个线程 也就是说 countDown运行了六次 【-6】
            new Thread(new DownLatchThread()).start();
        }
        // await(), 等待6个线程全部执行完
        downLatch.await();

        // 打印 可以看出这句话是六个线程运行完成之后才运行的
        System.out.println("主线程运行");
    }

运行的结果:

Thread: 11
Thread: 12
Thread: 13
Thread: 14
Thread: 15
Thread: 16
主线程运行

从上面的代码来看我们初始化了CountDownLatch的大小为6,然后启动6个线程,这六个线程都调用一次countDown()方法。从结果来看,主线程是等待6个线程运行完之后才执行的,这也体现了CountDownLatch的作用。【如果我启动五个线程,也就是调用五次countDown()方法,这时线程会一直阻塞。】

CyclicBarrier

CyclicBarrier是什么

从字面意思上来看CyclicBarrier就是循环(Cyclic)的屏障(Barrier);
作用:让一组线程达到某个屏障,被阻塞,一直到组内最后一个线程达到屏障时,屏障开放,所有被阻塞的线程会继续运行。

CyclicBarrier如何使用

方法说明

  • new CyclicBarrier(6):实例化CyclicBarrier时传入参数count,count可以理解为线程的数量
  • new CyclicBarrier(int count, Runnable runnable):当最后一个一组中的最后一个线程任务执行完后,指定一个任务执行
  • await():调用的线程阻塞,直到一组线程中的最后一个线程调用await(),所有被awati()方法阻塞的线程都会被放行
  • reset():将屏障重置为其初始状态。如果所有参与者目前都在屏障处等待,则它们将返回,同时抛出一个BrokenBarrierException。

具体使用:

    /**
     * 实例化CyclicBarrier
     */
    private static CyclicBarrier cyclicBarrier = new CyclicBarrier(6);

    /**
     * 工作线程
     */
    static class BarrierThread implements Runnable {

        @Override
        public void run() {
            try {
                // 不是最后一个线程,阻塞
                System.out.println("thread: "+ Thread.currentThread().getId() + " await.");
                cyclicBarrier.await();
                // 只有当最后一个线程的调用await之后,每个线程await()下面的代码才会执行
                System.out.println("do something .");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 6; i++) {
            new Thread(new BarrierThread()).start();
        }
        System.out.println("主线程运行");
    }

运行结果

主线程运行
thread: 13 await.
thread: 11 await.
thread: 12 await.
thread: 14 await.
thread: 15 await.
thread: 16 await.
do something .
do something .
do something .
do something .
do something .
do something .

这段代码也很简单,实例化一个大小为6的CyclicBarrier,启动6个线程每个线程都调用了await()方法。从打印的结果来看,当线程16运行之前,线程11,12,13,14,15都是阻塞状态,线程16 执行了await()方法后。所有的线程都被放行,继续执行await()方法后的代码。

CyclicBarrier与CountDownLatch比较
  • CountDownLatch:一个线程(或者多个),等待另外N个线程完成某个事情之后才能执行;CyclicBarrier:N个线程相互等待,任何一个线程完成之前,所有的线程都必须等待。
  • CountDownLatch:一次性的;CyclicBarrier:可以重复使用。
  • CountDownLatch基于AQS;CyclicBarrier基于锁和Condition。本质上都是依赖于volatile和CAS实现的。

Semaphore

Semaphore是什么

字面意思:信号量
作用:控制同时访问某个特定资源的线程数量,用在流量控制

Semaphore如何使用

重要方法说明

  • new Semaphore(int permits):初始化时,传入许可证的数量;
  • acquire():获取许可证, -1;
  • release():归还许可证, +1;
  • hasQueuedThreads():是否有阻塞的线程;
  • getQueueLength():得到阻塞线程的数量;
  • availablePermits():可用许可证的数量;

具体使用

    /**
     * 座位数量10
     */
    private final Semaphore seatCount = new Semaphore(10);

    /**
     * 构造方式私有化
     */
    private UseSemaphoreDemo() {
    }

    private static UseSemaphoreDemo instance = null;

    private static UseSemaphoreDemo getInstance() {
        if (instance == null) {
            synchronized (UseSemaphoreDemo.class) {
                instance = new UseSemaphoreDemo();
            }
        }
        return instance;
    }

    static class WorkThread extends Thread {
        UseSemaphoreDemo semaphoreDemo = UseSemaphoreDemo.getInstance();

        @Override
        public void run() {
            try {
                // 获取座位使用权 就是调用 acquire() 方法
                semaphoreDemo.seatCount.acquire();
                System.out.println("线程Thread: " + Thread.currentThread().getId() +
                        "获取到使用权");
                if (semaphoreDemo.seatCount.hasQueuedThreads()) {
                    // 是否有等待的线程
                    System.out.println("等待的线程数量:" + semaphoreDemo.seatCount.getQueueLength());
                }
                // 获取使用权后休眠
                Thread.sleep(500 + Thread.currentThread().getId());
                // 归还座位的使用权 调用release()方法
                semaphoreDemo.seatCount.release();
                System.out.println("线程Thread: " + Thread.currentThread().getId() +
                        "归还了使用权");
                System.out.println("可用座位:" + semaphoreDemo.seatCount.availablePermits());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        // 60个线程去获取座位
        for (int i = 0; i < 60; i++) {
            new WorkThread().start();
        }
    }

上面代码的运行结果

线程Thread: 11获取到使用权
线程Thread: 12获取到使用权
线程Thread: 13获取到使用权
线程Thread: 14获取到使用权
线程Thread: 15获取到使用权
线程Thread: 16获取到使用权
线程Thread: 17获取到使用权
线程Thread: 18获取到使用权
线程Thread: 19获取到使用权
线程Thread: 20获取到使用权
线程Thread: 11归还了使用权
线程Thread: 21获取到使用权
可用座位:0
等待的线程数量:49
线程Thread: 12归还了使用权
线程Thread: 22获取到使用权
可用座位:0
等待的线程数量:48
线程Thread: 13归还了使用权
线程Thread: 23获取到使用权
...

上面代码的意思:一共10个座位,60个线程去获取使用权。
从控制台打印的结果来看:前10个线程迅速的拿到了座位的使用权,而之后的线程必须要等到拿到使用权的线程归还使用权后才能得到。这个也说明了Semaphore的作用。

猜你喜欢

转载自blog.csdn.net/qq_38345031/article/details/84571474