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()方法重置计数器的屏障数。