J.U.C常见的并发工具集
以下是学习中的一些笔记记录,如果有错误希望得到你的指正~ 同时也希望对你有点帮助~
Countdownlatch
共享锁的实现,可以允许多个线程同时抢占到锁,然后等到计数器归零的时候,同时唤醒持有锁的线程
/**
* CountDownLatch 就相当于是一个计数器,当计数归0,释放所有被阻塞的线程,通过AQS共享锁实现
*
* CountDownLatch quick start 子线程countdown main线程 await
* 所有子线程执行完之后countdown计数为0,才执行main线程,阻塞一个线程
*
* @author zdp
* @date 2022-06-02 10:03
*/
public class CountDownLatchTestOne {
static CountDownLatch countDownLatch = new CountDownLatch(2);
public static void main(String[] args) throws InterruptedException {
ThreadOne one = new ThreadOne();
ThreadTwo two = new ThreadTwo();
one.start();
two.start();
System.out.println("main 线程阻塞....");
countDownLatch.await();
System.out.println("main 线程释放....");
}
static class ThreadOne extends Thread {
@Override
@SneakyThrows
public void run() {
TimeUnit.SECONDS.sleep(3);
countDownLatch.countDown();
System.out.println("ThreadOne 释放....");
}
}
static class ThreadTwo extends Thread {
@Override
@SneakyThrows
public void run() {
TimeUnit.SECONDS.sleep(5);
countDownLatch.countDown();
System.out.println("ThreadTwo 释放....");
}
}
}
/**
* CountDownLatch quick start main线程countdown 子线程 await
* 阻塞所有子线程,main线程中countdown计数为0之后,再释放所有阻塞的子线程,阻塞多个线程
*
* @author zdp
* @date 2022-06-06 09:49
*/
public class CountDownLatchTestTwo {
static CountDownLatch countDownLatch = new CountDownLatch(1);
public static void main(String[] args) throws InterruptedException {
ThreadOne one = new ThreadOne();
ThreadTwo two = new ThreadTwo();
one.start();
two.start();
System.out.println("main 线程阻塞....");
TimeUnit.SECONDS.sleep(2);
countDownLatch.countDown();
System.out.println("main 线程释放....");
}
static class ThreadOne extends Thread {
@Override
@SneakyThrows
public void run() {
System.out.println("ThreadOne 阻塞....");
countDownLatch.await();
System.out.println("ThreadOne 释放....");
}
}
static class ThreadTwo extends Thread {
@Override
@SneakyThrows
public void run() {
System.out.println("ThreadTwo 阻塞....");
countDownLatch.await();
System.out.println("ThreadTwo 释放....");
}
}
}
Cyclicbarrier
/**
* CyclicBarrier quick start 可重复的栅栏
* CyclicBarrier 就相当于CountDownLatch 的阻塞多个线程,当多个子线程都执行完都到达栅栏,然后一起释放所有子线程
*
* @author zdp
* @date 2022-06-02 10:04
*/
public class CyclicBarrierTest {
public static void main(String[] args) {
//不带回调
CyclicBarrier cyclicBarrier = new CyclicBarrier(4);
for (int i = 0; i < 4; i++) {
new Waiter(cyclicBarrier).start();
}
}
static class Waiter extends Thread {
private CyclicBarrier cyclicBarrier;
public Waiter(CyclicBarrier cyclicBarrier){
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
try {
//相当于 CountDownLatch 的countdown -1操作
TimeUnit.SECONDS.sleep(2);
System.out.println("子线程" + Thread.currentThread().getName() + "执行完毕,等待其他线程执行任务....");
cyclicBarrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
}
}
/**
* CyclicBarrier quick start 带回调的 CyclicBarrier
* 所有子线程执行完,
* @author zdp
* @date 2022-06-06 10:38
*/
public class CyclicBarrierCallbackTest {
public static void main(String[] args) {
//带回调
CyclicBarrier callBack = new CyclicBarrier(4, () -> System.out.println("其他线程任务执行完毕,执行回调任务...."));
for (int i = 0; i < 4; i++) {
new CyclicBarrierTest.Waiter(callBack).start();
}
}
static class Waiter extends Thread {
private CyclicBarrier cyclicBarrier;
public Waiter(CyclicBarrier cyclicBarrier){
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
try {
//相当于 CountDownLatch 的countdown -1操作
TimeUnit.SECONDS.sleep(2);
System.out.println("子线程" + Thread.currentThread().getName() + "执行完毕,等待其他线程执行任务....");
cyclicBarrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
}
}
Semaphore
/**
* Semaphore 相当于一个限制并发访问的容器,达到限制资源数量会阻塞,通过AQS共享锁实现
*
* Semaphore quick start
*
* @author zdp
* @date 2022-06-02 10:03
*/
public class SemaphoreTest {
public static void main(String[] args) {
//停车场5个车位
Semaphore semaphore = new Semaphore(5);
//20辆车进停车场停车
for (int i = 1; i <= 20; i++) {
new Car(i, semaphore).start();
}
}
static class Car extends Thread {
/**
* 车辆序号
*/
private int serialNumber;
/**
* 停车场
*/
private Semaphore semaphore;
public Car(int serialNumber, Semaphore semaphore){
this.serialNumber = serialNumber;
this.semaphore = semaphore;
}
@Override
public void run() {
try {
//抢占一个车位
semaphore.acquire();
System.out.println("第" + serialNumber + "辆车,进入停车场...");
TimeUnit.SECONDS.sleep(1);
System.out.println("第" + serialNumber + "辆车,离开停车场...");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//释放一个车位
semaphore.release();
}
}
}
}
Exchanger
/**
* Exchanger 基础使用
*
* Exchanger 用于线程之间数据的交换。它提供一个同步点,在这个同步点两个线程可以交换彼此的数据。这两个线程通过exchange方法交换数据,
* 如果第一个线程先执行exchange方法,它会一直等待第二个线程也执行exchange,当两个线程都到达同步点时,这两个线程就可以交换数据,
* 将本线程生产出来的数据传递给对方。因此使用Exchanger的重点是成对的线程使用exchange()方法,当有一对线程达到了同步点,就会进行交换数据。因此该工具类的线程对象是成对的
*
* public V exchange(V x); 用于交换,启动交换并等待另一个线程调用exchange
*
* public V exchange(V x, long timeout, TimeUnit unit); 用于交换,启动交换并等待另一个线程调用exchange,超过超时时间便停止等待
*
* Exchanger 必须是线程成对使用,如果不是成对使用将导致长时间阻塞
*
* @author zdp
* @date 2022-07-26 16:22
*/
@Slf4j
public class ExchangerExample {
public static void main(String[] args) {
Exchanger<String> exchanger = new Exchanger<>();
ExecutorService executor = Executors.newFixedThreadPool(10);
executor.submit(() -> {
try {
log.info("线程【" + Thread.currentThread().getName() + "】开始执行...");
// 让线程2先达到同步点
TimeUnit.SECONDS.sleep(3);
String resultOne = "Thread One Result....";
log.info("线程【" + Thread.currentThread().getName() + "】到达同步点...准备交换的数据是: " + resultOne);
String threadOneResult = exchanger.exchange(resultOne);
log.info("线程【" + Thread.currentThread().getName() + "】获取的交换数据是{}", threadOneResult);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("线程【" + Thread.currentThread().getName() + "】运行结束");
});
executor.submit(() -> {
String resultTwo = "Thread Two Result....";
try {
log.info("线程【" + Thread.currentThread().getName() + "】开始执行...");
log.info("线程【" + Thread.currentThread().getName() + "】达到同步点...准备交换的数据是: " + resultTwo);
String threadTwoResult = exchanger.exchange(resultTwo);
log.info("线程【" + Thread.currentThread().getName() + "】获取的交换数据是{}", threadTwoResult);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("线程【" + Thread.currentThread().getName() + "】运行结束");
});
executor.submit(() -> {
String resultThree = "Thread Three Result....";
try {
log.info("线程【" + Thread.currentThread().getName() + "】开始执行...");
log.info("线程【" + Thread.currentThread().getName() + "】达到同步点...准备交换的数据是: " + resultThree);
String threadThreeResult = exchanger.exchange(resultThree);
log.info("线程【" + Thread.currentThread().getName() + "】获取的交换数据是{}", threadThreeResult);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("线程【" + Thread.currentThread().getName() + "】运行结束");
});
executor.submit(() -> {
String resultFour = "Thread Four Result....";
try {
log.info("线程【" + Thread.currentThread().getName() + "】开始执行...");
log.info("线程【" + Thread.currentThread().getName() + "】达到同步点...准备交换的数据是: " + resultFour);
String threadFourResult = exchanger.exchange(resultFour);
log.info("线程【" + Thread.currentThread().getName() + "】获取的交换数据是{}", threadFourResult);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("线程【" + Thread.currentThread().getName() + "】运行结束");
});
executor.shutdown();
}
}