常用并发工具类的使用。
CountDownLatch
CountDownLatch是一个计数器,当计数器的值大于0时,执行等待方法await,阻塞直到计数器的值等于0时,才放行。
Lach有门闩的意思,可以把它理解成一道栅栏,举个生活中的例子,运动员在起跑线上,等待发号员口令,这是运动员调用的是await方法。发号员数"3、2、1“时,调用了三次downCount方法。当值为0时,运动员就开跑。
public class CoundownLatchTest {
private static final CountDownLatch countDownLatch = new CountDownLatch(5);
private static List<String> bossList = new ArrayList<>();
public static void main(String[] args) throws InterruptedException {
new AssassinateThread("杀手一", "吉诺维斯家族首领").start();
new AssassinateThread("杀手二", "波纳诺家族首领").start();
new AssassinateThread("杀手三", "科洛博家族首领").start();
new AssassinateThread("杀手四", "卢凯塞家族首领").start();
new AssassinateThread("杀手五", "甘比诺家族首领").start();
countDownLatch.await();
// 执行到这里,理论上全部首领刺杀成功
System.out.println("刺杀成功名单:");
for (String bossName : bossList) {
System.out.print(bossName + " ");
}
}
private static class AssassinateThread extends Thread {
private String bossName;
public AssassinateThread(String name, String bossName) {
super(name);
this.bossName = bossName;
}
@Override
public void run() {
bossList.add(bossName);
countDownLatch.countDown(); // 计数器减一
}
}
}
CyclicBarrier
Cyclicbarrier叫做循环栅栏,顾名思义,就是可以被循环使用。设立一个屏障,待所有线程到达这个屏障之后,才能执行下一步的代码。注意区别于CountdownLatch的用法,CountdownLatch是一个倒计时器。
public class PlayBasketball {
// 等待六个人都到的时候,就可以3v3了。
private static CyclicBarrier cyclicBarrier = new CyclicBarrier(6, new Play3v3Thread());
public static void main(String[] args) {
System.out.println("永和九年,天朗气清,惠风和畅,与众球星会于天体边之球场,修禊事也。");
new ReportThread("我").start();
new ReportThread("迈克尔乔丹").start();
new ReportThread("科比布莱恩特").start();
new ReportThread("勒布朗詹姆斯").start();
new ReportThread("蒂姆邓肯").start();
new ReportThread("凯文杜兰特").start();
}
private static class Play3v3Thread extends Thread {
@Override
public void run() {
System.out.println("所有人到齐,开始3v3");
}
}
private static class ReportThread extends Thread {
private String name;
public ReportThread(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(name + "到了");
try {
cyclicBarrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
}
}
Exchanger
用于线程之前交换信息,比如做买卖,有买有卖,有得必有失。
public class ExchangerTest {
// exchanger可用来线程之前交换信息,比如做买卖,对于卖家,他收了钱。对比买家,他得到货物。
private static final Exchanger<String> exchanger = new Exchanger<>();
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(2);
threadPool.execute(new Runnable() {
@Override
public void run() {
String phone = "iphone11";
try {
System.out.println("我是苹果旗舰店,我卖出" + phone + ",挣了" + exchanger.exchange(phone));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
threadPool.execute(new Runnable() {
@Override
public void run() {
String money = "5999";
try {
System.out.println("我花了"+ money + "买了一部" + exchanger.exchange(money));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
Semaphore
semaphore用来控制一组资源的并发使用,有点类似synchronic关键字,但是semaphore可以控制n个线程同时访问资源。举个例子,大家都用过公共厕所吧,假设厕所有5个蹲厕,只要没人就可以进去大号。那么就可以用semaphore模拟公共厕所大号的逻辑。注:这是一段有味道的代码。
public class SemaphoreTest {
// 厕所有5个蹲厕,全部占满就得等待
private static final Semaphore wc = new Semaphore(5);
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
// 假设有100个人要同时使用厕所
new ShitThread().start();
}
}
/**
* 大号线程
*/
static class ShitThread extends Thread {
@Override
public void run() {
try {
wc.acquire();
System.out.println(getName() + "开始大号");
Thread.sleep(5000); // 假设消耗5s,你也可以给个随机数
System.out.println(getName() + "结束大号");
wc.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}