JUC常用的4种工具、CountDownLatch、CyclicBarrier、Semaphore、Exchanger、常用方法

 

 

 

JUC常用工具(组件)类 JDK 1.5

都实现了AQS类

 

1、CountDownLatch

java.util.concurrent.CountDownLatch 类,是一个减计数器

构造方法

  • public CountDownLatch(int count) 设置计数的总数

常用方法

  • public void await() throws InterruptedException 等待计数为0,计数为0,才可以执行之后的代码

  • public boolean await(long timeout,TimeUnit unit) throws InterruptedException

    timeout:等待时间

    unit:timeout参数的时间单位

    返回结果:true计数为0;false到达了时间且计数还没有为0

  • public void countDown() 计数减1

  • public long getCount() 返回当前计数

public class CountDownLatchTest {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(6); // 设置总数为6

        for (int i = 1; i <= 6; i++) {
            new Thread(()->{
                countDownLatch.countDown(); // -1
                System.out.println(Thread.currentThread().getName() + " Go out...");
            },String.valueOf(i)).start();
        }

        countDownLatch.await(); // 当计数为0,才会执行下面的代码

        System.out.println("所有线程都执行完毕了...");
    }
}

 

输出:

1 Go out...
2 Go out...
3 Go out...
4 Go out...
5 Go out...
6 Go out...
所有线程都执行完毕了..
 

2、CyclicBarrier

java.util.concurrent.CyclicBarrier 类,是一个加计数器

构造方法

  • public CyclicBarrier(int parties) 设置一个需要到达数量的值,到达了parties这个值,不会执行特定的动作
  • public CyclicBarrier(int parties, Runnable barrierAction) 设置一个需要到达数量的值,到达了parties这个值,会执行特定的动作

常用方法

  • public int await() throws InterruptedException,BrokenBarrierException await方法,该线程进入阻塞状态,屏障值就+1,阻塞线程到达了屏障设定的parties数,就会执行构造器中第二参数barrierAction的动作(第二个参数是Runable接口的实现,通过调用run方法执行)
  • public int getParties() 获得需要达到parties的值
public class CyclicBarrierTest {
    public static void main(String[] args) {
        // 创建一个加计数器
        CyclicBarrier cyclicBarrier = new CyclicBarrier(6,()-> System.out.println("所有规定的线程都进入到了阻塞状态,达到了屏障"));

        for (int i = 1; i <= 6; i++) {
            final int num = i;
            new Thread(()->{
                System.out.println(Thread.currentThread().getName() + " 执行了");
              // await方法,该线程进入阻塞状态,屏障值就+1,阻塞线程到达了屏障设定6,就会执行构造器中第二参数的动作(第二个参数是Runable接口的实现,通过调用run方法执行)
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " 继续执行");
            }, String.valueOf(i)).start();
        }
    }
}

 

输出:

1 执行了
2 执行了
3 执行了
4 执行了
5 执行了
6 执行了
所有规定的线程都进入到了阻塞状态,达到了屏障
6 继续执行
1 继续执行
4 继续执行
3 继续执行
2 继续执行
5 继续执行

 

 

3、Semaphore

java.util.concurrent.Semaphore 类,就是一个许可证(信号量)

构造方法

  • public Semaphore(int permits) 设置许可证的个数及非公平公平设置
  • public Semaphore(int permits,boolean fair) 设置许可证的个数及给定公平设置

常用方法

  • public void acquire() throws InterruptedException 获得许可证,未获取到的线程等待。
  • public void release() 释放许可证
public class SemaphoreTest {
    public static void main(String[] args) {
        // 设置许可证个数。 用于 限流!
        Semaphore semaphore = new Semaphore(3);
        for (int i = 1; i <= 6; i++) {
            new Thread(()->{
                try {
                    // 线程获取许可证,未获取到的等待。
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + " 获得许可证");
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread().getName() + " 释放许可证");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    // 释放许可证
                    semaphore.release();
                }
            }, String.valueOf(i)).start();
        }
    }
}

 

 

4、Exchanger

Exchanger类源于java.util.concurrent包,它可以在两个线程之间传输数据,Exchanger中的public V exchange(V x)方法被调用后等待另一个线程到达交换点(如果当前线程没有被中断),然后将已知的对象传给它,返回接收的对象。

如果担心线程一直等待,可以使用exchange(V x, long timeout, TimeUnit unit)方法设置等待时长。

public class ExchangerTest {
    private Exchanger<String> exchanger = new Exchanger<>();
    private ExecutorService executorService = Executors.newFixedThreadPool(2);

    @Test
    public void test(){
        executorService.execute(()->{
            try {
                Thread.currentThread().setName("0");
                String a = "线程A";
                String B = exchanger.exchange(a); // 与调用这个方法的另一个线程进行数据的交换,
                                                  // 调用了该方法之后,会一直阻塞等待另一个线程进行数据交换
                System.out.println(Thread.currentThread().getName()+": "+ B);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        executorService.execute(()->{
            try {
                Thread.currentThread().setName("1");
                String b = "线程B";
                String A = exchanger.exchange(b);
                System.out.println(Thread.currentThread().getName()+": "+ A);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        });
    }
}

 

- CountDownLatch 与 CyclicBarrier 的区别

CountDownLatch 是减数的计数器。当值为0后,才使得调用了CountDownLatch的await()方法的线程被唤醒,继续执行之后的任务。并且CountDownLatch不可以重新设置计数总数值

CyclicBarrier 是加数的计数器,到达了指定的屏障数,才可以被唤醒继续执行。通过线程通过调用CyclicBarrier的await()方法,被阻塞之后,即增加了一个屏障。当达到了屏障指定的数,就会执行特定的动作 (构造器第二个参数barrierAction) 。特定动作执行完了之后,被阻塞的线程会被唤醒,各线程继续执行await()方法之后的任务。CyclicBarrier可以通过reset()方法重置计数器的屏障数

 

posted @ 2020-06-14 16:53  张还行  阅读(255)  评论(0编辑  收藏  举报