手敲了一下并发包中三个辅助类的使用,加深了理解。
1.CountDownLatch(减少计数)
- CountDownLatch主要有两个方法,当一个或多个线程调用await方法时,这些线程会阻塞。
- 其它线程调用countDown方法会将计数器减1(调用countDown方法的线程不会阻塞),
- 当计数器的值变为0时,因await方法阻塞的线程会被唤醒,继续执行。
测试代码:秦灭六国,一个个灭掉,最终统一
package com.ran.juc;
import java.util.concurrent.CountDownLatch;
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <=6 ; i++) {
int finalI = i;
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"\t 国被灭");
countDownLatch.countDown();
},CountryEnum.forEach_CoutryEnum(i).getRetMessage()).start();
}
countDownLatch.await();
System.out.println("秦国灭六国,统一天下");
}
}
创建一个拿国名的枚举工具类:
package com.ran.juc;
import lombok.Getter;
public enum CountryEnum {
ONE(1,"齐"),TWO(2,"楚"),THREE(3,"燕"),FOUR(4,"赵"),FIVE(5,"魏"),SIX(6,"韩");
/**
* 这里的 CountryEnum 相当于mysql中的数据库名字
*
* mysql dbName = CountryEnum
* table one
* ID userName age ....
* 1 齐 109
*
* ONE(1,"齐",v2,v3,v4,v5)
*/
@Getter private Integer retCode;
@Getter private String retMessage;
CountryEnum(Integer retCode, String retMessage) {
this.retCode = retCode;
this.retMessage = retMessage;
}
public static CountryEnum forEach_CoutryEnum(int index){
CountryEnum[] myArray = CountryEnum.values();
for (CountryEnum element:
myArray) {
if (index == element.getRetCode()){
return element;
}
}
return null;
}
}
执行结果:
齐 国被灭
楚 国被灭
燕 国被灭
赵 国被灭
魏 国被灭
韩 国被灭
秦国灭六国,统一天下
2.CyclicBarrier
- CyclicBarrier
- 的字面意思是可循环(Cyclic)使用的屏障(Barrier)。它要做的事情是,
- 让一组线程到达一个屏障(也可以叫同步点)时被阻塞,
- 直到最后一个线程到达屏障时,屏障才会开门,所有
- 被屏障拦截的线程才会继续干活。
- 线程进入屏障通过CyclicBarrier的await()方法。
测试代码:集齐七颗龙珠召唤神龙
package com.ran.juc;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierDemo {
private static final int num = 7;
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(num,()->{
System.out.println("已经集齐七颗龙珠召唤神龙");
});
for (int i = 1; i <=7 ; i++) {
int finalI = i;
new Thread(()->{
System.out.println("收集到第"+"\t"+ finalI+"颗龙珠");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}
执行结果:
收集到第 1颗龙珠
收集到第 5颗龙珠
收集到第 6颗龙珠
收集到第 7颗龙珠
收集到第 2颗龙珠
收集到第 3颗龙珠
收集到第 4颗龙珠
已经集齐七颗龙珠召唤神龙
3.Semaphore
在信号量上我们定义两种操作:
-
acquire(获取) 当一个线程调用acquire操作时,它要么通过成功获取信号量(信号量减1),要么一直等下去,直到有线程释放信号量,或超时。
-
release(释放)实际上会将信号量的值加1,然后唤醒等待的线程。
-
信号量主要用于两个目的,一个是用于多个共享资源的互斥使用,另一个用于并发线程数的控制。
测试代码:争抢车位(资源不够用)
package com.ran.juc;
import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class SemaphoreDemo {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);//模拟3个停车位
for (int i = 1; i <=6 ; i++) {//模拟6辆车
new Thread(()->{
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+"\t抢到了车位");
TimeUnit.SECONDS.sleep(new Random().nextInt(5));
System.out.println(Thread.currentThread().getName()+"\t------离开");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
semaphore.release();
}
},String.valueOf(i)).start();
}
}
}
执行结果:
2 抢到了车位
1 抢到了车位
3 抢到了车位
3 ------离开
4 抢到了车位
4 ------离开
5 抢到了车位
2 ------离开
6 抢到了车位
5 ------离开
1 ------离开
6 ------离开