JUC的强大辅助类
JUC的强大辅助类
juc中提供了常用的辅助类,通过这些辅助类,可以很好的解决线程数量过多时,Lock锁的频繁操作这三种辅助类为:
- 1.CountDownLatch,减少计数。
- 2.CyclicBarrier,循环栅栏。
- 3.Semaphore,信号灯。
减少计数器(CountDownLatch)
CountDownLatch类可以设置一个计数器,然后通过countDown方法来进行-1操作,使用await方法等待计数器的值<=0,然后继续执行await方法之后的语句。
- 1.CountDownLatch,有两个主要方法是await()和countDown(),当一个或多个线程调用await()时,这些线程会阻塞。
- 2.线程调用countDown()时,计数器的值会-1(调用countDown()方法不会阻塞)。
- 3.当计数器的值变为0时,因计数器.await(),阻塞的线程,会被唤醒继续执行。
案例及代码实现
/**
* @author 长名06
* @version 1.0
* 演示CountDownLatch
*/
public class CountDownLatchDemo {
//6位同学,陆续离开教室后,班长才锁门
public static void main(String[] args) throws InterruptedException {
// 此代码不能实现案例要求,因为mian线程和新增的线程间不是互斥状态,并行执行,
// 很可能班长已经锁门,但是还有同学未离开教室
// for (int i = 0; i < 6; i++) {
// new Thread(() ->{
// System.out.println(Thread.currentThread().getName() + "位同学离开教室");
// },String.valueOf(i + 1)).start();
// }
// System.out.println(Thread.currentThread().getName() + "班长锁门了");
//第一步,创建计数器,定义初始值
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 0; i < 6; i++) {
new Thread(() ->{
//需要执行的代码,一定要写在进行-1操作前,因为计数器的值一旦变为0,就会立刻唤醒,因其await()等待的线程,
//写在之后的话,可能就会出现,主线程执行,其他线程才执行的情况
//第二步,执行线程需要的操作
System.out.println(Thread.currentThread().getName() + "位同学离开教室");
//第三步,进行-1操作
countDownLatch.countDown();//对设定的初始值,进行-1操作
},String.valueOf(i + 1)).start();
}
//第四步,使其他线程等待
countDownLatch.await();
System.out.println(Thread.currentThread().getName() + "班长锁门了");
}
}
循环栅栏(CyclicBarrier)
CyclicBarrier是循环阻塞的意思,在使用中,Cyclic构造方法,第一个参数是目标数,每次执行CyclicBarrier一次,目标数会+1,只有达到了目标数,才会执行,传入的第二个参数barrierAction 中的run方法。可以将CyclicBarrier.await()看作一次目标数+1并且阻塞当前线程的复合操作,且该阻塞方法,是在目标数达成后,统一唤醒因该方法阻塞的线程,继续执行执行每个线程的操作。
案例及代码实现
/**
* @author 长名06
* @version 1.0
* 演示循环栅栏CyclicBarrier
* 集齐七颗龙珠案例
*/
public class CyclicBarrierDemo {
//集齐七颗龙珠
private static final int NUMBER = 7;
public static void main(String[] args) {
//第一步,设定目标数,且指定目标数达成后,要执行的方法
CyclicBarrier cyclicBarrier = new CyclicBarrier(NUMBER, () -> {
System.out.println("七颗龙珠被集齐了");
});
for (int i = 1; i <= 7; i++) {
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() + "星龙珠被收集到了");
//第二步+1,且阻塞线程
cyclicBarrier.await();
System.out.println(Thread.currentThread().getName() +"测试");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
},String.valueOf(i)).start();
}
}
}
信号灯(Semaphore)
Semaphore的构造方法,中传入的第一个参数是最大信号量(可以看作线程池中的最大线程数),每个信号量初始化的数目,也就是能分发的最大许可证,使用acquire()方法,获取许可证,release()方法释放许可证。
案例及代码实现
/**
* @author 长名06
* @version 1.0
* 信号灯 信号量
*/
public class SemaphoreDemo {
//实现6辆车,停入3个车位
public static void main(String[] args) {
Semaphore semaphore = new Semaphore( 3);
for (int i = 1; i < 7; i++) {
new Thread(() -> {
try {
// System.out.println(Thread.currentThread().getName() + "号车寻找车位中");
semaphore.acquire();//获取信号量
System.out.println(Thread.currentThread().getName() + "号车,停车成功");
TimeUnit.SECONDS.sleep(new Random().nextInt(5));//随机等待几秒
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
System.out.println(Thread.currentThread().getName() + "号车,离开驶出车位");
semaphore.release();//释放信号量操作
}
},String.valueOf(i)).start();
}
}
}
只是为了记录自己的学习历程,且本人水平有限,不对之处,请指正。