并发编程—工具类

文章目录

  • 同步工具类
    • CountDownLatch
    • Semaphore
    • Exchanger
    • CyclicBarrier
    • Phaser

同步工具类


CountDownLatch

  1. 使用场景
    CountDownLatch是一个计数器,当计数器的数值被其他的线程减为0,才会执行主线程。若多个线程阻塞在await(),则countDown()到state为0时一次性唤醒所有线程,如图所示。
    并发编程—工具类_第1张图片
  2. 使用示例
// 定义数值为5的计数器
CountDownLatch latch = new CountDownLatch(5);
// 计数减1
latch.countDown();
// 当前线程等待
latch.await();
  1. 原理探索
    CountDownLatch原理和锁原理类似,基于AQS,但没有公平和非公平之分,CountDownLatch类的继承体系如图所示。
    并发编程—工具类_第2张图片

Semaphore

  1. 使用场景
    Semaphore即信号量,提供资源数量的并发访问控制。如图所示,若有n个线程来获取Semaphore的10份资源(n > 10),这n个线程中只有10个线程可获取,其他线程都进入阻塞,直到有线程释放了资源,才能获取。
    并发编程—工具类_第3张图片
  2. 使用示例
// 参数一:5份共享资源。
// 参数二:是否公平方式,一般非公平抢占效率较高。
Semaphore myResources = new Semaphore(5, true);

// 工作线程每获取1份资源,该对象进行记录。
myResources.acquire();

// 工作线程每归还1份资源,该对象进行记录。
myResources.release();

/*
释放指定数目的资源,并将资源归还。
若线程需获取N个许可,在有N个许可可用之前,该线程阻塞。
*/
semaphore.release(2);

/*
获取指定数目的许可。
若可用许可数目不够,则线程阻塞,直到被中断。
*/
semaphore.acquire(3);
  1. 原理探索
    Semaphone原理和锁十分类似,基于AQS,有公平和非公平之分。Semaphore类的继承体系如图所示。
    并发编程—工具类_第4张图片

Exchanger

  1. 使用场景
    Exchanger主要用于线程之间交换数据。
  2. 使用实例
// 创建一个多线程共用的exchange对象
// Run方法调exchange,并把数据作为参数进行传递,返回另外一个线程调用exchange传进入的参数值
Exchanger<String> exchanger = new Exchanger<>();

// 如果没有其他线程调用exchange,则线程阻塞,直到有其他线程调用exchange后恢复。
String otherData = exchanger.exchange("需要交换的数据1/2/3");

若3个线程并发地调用exchange(),则会两两交互数据。

  1. 原理探索
    Exchanger核心机制和Lock类似,使用CAS+park/unpark。

CyclicBarrier

  1. 使用场景
    CyclicBarrier类用于协调多个线程同步执行操作的场合。
    例如招聘场景:10位毕业生到公司应聘。首先,等10人到齐后,开始笔试;笔试结束后,再一共参加面试。若把10个人看为10个线程,10个线程之间的同步过程如下图所示:
    并发编程—工具类_第5张图片
    整个过程,需要2个同步点:第1个同步点,等待所有毕业生到达公司,再开始笔试;第2个同步点:等待所有毕业生都结束笔试,再一起进行面试环节。
  2. 使用示例
// 创建
CyclicBarrier barrier = new CyclicBarrier(10);
// 等待
barrier.await();
  1. 原理探索
    CyclicBarrier基于ReentrantLock+Condition实现。
    CyclicBarrier是可以被重用的。
    CyclicBarrier 会响应中断。

Phaser

  1. 使用场景
    JDK7新增了同步工具类Phaser,功能类似CyclicBarrier和CountDownLatch,但更加强大。
    (1)Phaser可替代CountDownLatch。
    (2)Phaser可替代CyclicBarrier。
    (3)Phaser的新功能:动态调整线程数量;多层次Phaser构建;
  • CyclicBarrier所设置的同步线程数量在构造方法中指定后不能更改,而Phase可在运行期间动态地调整同步的线程数量。
  • 如图所示,多个Phaser可以组成如下图所示的树状结构。
    并发编程—工具类_第6张图片
    树状Phaser的每个节点,可当作成一个独立的Phaser来看待,父类Phaser并不感知子类Phaser的存在,当子类Phaser中注册的参与者数量大于0,则把自己向父节点注册;当子类Phaser中注册的参与者数量等于0时,则自动向父节点解除注册。父Phaser把子Phaser当作一个正常参与的线程。
  1. 使用示例
// 替代CountDownLatch
Phaser phaser = new Phaser(10);
// 到达计数
phaser.arrive();
// 主线程等待
phaser.awaitAdvance(phaser.getPhase());

//替代CyclicBarrier
Phaser phaser = new Phaser(5);
// 到达并等待。arriveAndAwaitAdance()是arrive()与awaitAdvance(int)的组合,表示“自己已到达同步点,同时等待所有人都到达这个同步点,再一起执行”。
phaser.arriveAndAwaitAdvance();
// 主线程等待
phaser.awaitAdvance(phaser.getPhase());

// Phaser提供了下面这些方法来增加、减少所要同步的线程个数。
register() // 注册一个
bulkRegister(int parties) // 注册多个
arriveAndDeregister()  // 解除注册

// 树状Phaser构建
Phaser root = new Phaser(2);
Phaser c1 = new Phaser(root, 3);
Phaser c2 = new Phaser(root, 2);
Phaser c3 = new Phaser(c1, 0);
  1. 原理探索
    Phaser并没有基于AQS来实现。
    持续更新中…

你可能感兴趣的:(并发编程,java,后端,多线程,并发编程)