JUC的三个辅助类

424 阅读3分钟

CountDownLatch

  • countDownLatch这个类使一个线程等待其他线程各自执行完毕后再执行。
  • 是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了。
  • CountDownLatch主要有2个方法,当一个或多个线程调用await()方法时,这些线程会阻塞
  • 其他线程调用countDown()方法会将计数器减1(调用countDown方法的线程不会阻塞),
  • 当计数器变为0时,因await方法阻塞的线程会被唤醒,继续执行

他的构造方法

  • 示例
 public class CountDownLatchDemo {

    public static void main(String[] args) throws InterruptedException {

        //假如需要计数6个
        CountDownLatch countDownLatch = new CountDownLatch(6);

        //6次请求,只有6次请求走完,才输出main线程的操作
        for (int i = 1; i <= 6; i++) {
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+"离开");
                //计数器减少1
                countDownLatch.countDown();
            },String.valueOf(i)).start();

        }
        //等待计数器归零
        countDownLatch.await();
        System.out.println(Thread.currentThread().getName()+"离开");
    }

}

CyclicBarrier

  • CyclicBarrier可循环使用的屏障,让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障时屏障才会开门 ,所有被屏障拦截的线程才会继续运行。

  • CyclicBarrier和CountDownLatch一样,都是关于线程的计数器,相比CountDownLatch,该JUC辅助类做加法,只要到了规定数,其内部的方法就执行

构造方法

  • 示例
public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        //假如需要计数6个
        CountDownLatch countDownLatch = new CountDownLatch(6);

        //6次请求,只有6次请求走完,才输出main线程的操作
        for (int i = 1; i <= 6; i++) {
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+"离开");
                //计数器减少1
                countDownLatch.countDown();
            },String.valueOf(i)).start();
        }
        //等待计数器归零
        countDownLatch.await();
        System.out.println(Thread.currentThread().getName()+"离开");
    }
}

Semaphore

Semaphore也是一个线程同步的辅助类,可以维护当前访问自身的线程个数,并提供了同步机制。使用Semaphore可以控制同时访问资源的线程个数,例如,实现一个文件允许的并发访问数。

信号量一般用2种操作

  • acquire(获取):当一个线程调用acquire操作时,它要么通过成功获取信号量(信号量-1), 要么一直等待,直到有现成释放信号量或者超时
  • release(释放):实际上会将信号量的值+1,然后唤醒等待的线程
public class SemaphoreDemo {
    public static void main(String[] args) {
        //3个资源位
        Semaphore semaphore = new Semaphore(3);

        for (int i = 1; i <= 6; i++) {
            new Thread(()->{
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() +"进来了");
                    //等待3秒
                    TimeUnit.SECONDS.sleep(3);
                    System.out.println(Thread.currentThread().getName()+"出去了");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    // 为什么释放要放在finally里呢
                    // 如果中途出现异常的话,不放在finally里面是有可能不会被执行的,但是放在finally里面是一定会被执行的
                    semaphore.release();
                }
            },String.valueOf(i)).start();
        }
    }
}

信号量主要用于

  • 共享资源的互斥使用
  • 并发线程数的控制 假如Semaphore的初始资源为1,就相当于synchronized