JUC辅助类
1.CountDownLatch
CountDownLatch 允许一个或多个线程等待一些特定的操作完成,而这些操作是在其它的线程中进行的,也就是说会出现 等待的线程 和 被等的线程 这样分明的角色;
CountDownLatch 构造函数中有一个 count 参数,表示有多少个线程需要被等待,对这个变量的修改是在其它线程中调用 countDown 方法,每一个不同的线程调用一次 countDown 方法就表示有一个被等待的线程到达,count 变为 0 时,latch(门闩)就会被打开,处于等待状态的那些线程接着可以执行;
CountDownLatch 是一次性使用的,也就是说latch门闩只能只用一次,一旦latch门闩被打开就不能再次关闭,将会一直保持打开状态,因此 CountDownLatch 类也没有为 count 变量提供 set 的方法;
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
//设置计数的初始值
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i =1;i<=6;i++){
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"号同学离开了教室");
//计数减一
countDownLatch.countDown();
},String.valueOf(i)).start();
}
//等带只有当计数减为0的时候才会执行后面的代码
countDownLatch.await();
System.out.println(Thread.currentThread().getName()+"班长关门");
}
}
2.CyclicBarrier
CyclicBarrier也叫同步屏障,在JDK1.5被引入,可以让一组线程达到一个屏障时被阻塞,直到最后一个线程达到屏障时,所以被阻塞的线程才能继续执行。 CyclicBarrier好比一扇门,默认情况下关闭状态,堵住了线程执行的道路,直到所有线程都就位,门才打开,让所有线程一起通过。
public class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier =new CyclicBarrier(7,()->{
System.out.println("所有运动员到了,准备起跑");//当阻塞被释放执行
});
for (int i=1;i<=7;i++){
new Thread(()->{
System.out.println("第"+Thread.currentThread().getName()+"位运动员到场");
try {
cyclicBarrier.await();
} catch (Exception e) {
throw new RuntimeException(e);
}
},String.valueOf(i)).start();
}
}
}
每个线程调用await方法告诉CyclicBarrier已经到达屏障位置,线程被阻塞,每阻塞一次CyclicBarrier内部的计数器就会加一,当计数器的值和自己创建时设置的值一样时,就会将阻塞的线程全部一起放出去然后执行()->{System.out.println("所有运动员到了,准备起跑"); }
3.Semaphore
一个计数信号量,从概念上将,信号量维护了一个许可集,如有必要,在许可可用前会阻塞每一个acquire(),然后在获取该许可。每个release()添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore只对可用许可的号码进行计数,并采取相应的行动
Semaphore(int permits) 创建具有给定的许可数和非公平的公平设置的Semapore,当permits为1时就和可重入锁一样
public Semaphore(int permits) {
// 默认创建非公平锁
sync = new NonfairSync(permits);
}
public Semaphore(int permits, boolean fair) {
// fair为true时,为公平锁
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
acquire()从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断
release()释放一个许可,将其返回给信号量
public void acquire() throws InterruptedException { //相当于上锁
// 阻塞当前线程
sync.acquireSharedInterruptibly(1);
}
public void release() { //相当于解锁
// 释放一个许可
sync.releaseShared(1);
}
设置许可数量 Semaphore semaphore = new Semaphore(3);
一般 acquire()都会抛出异常,release 在 finally 中执行
通过具体案例 6辆汽车,停3个车位
示例代码如下
public class SemaphoreTest {
public static void main(String[] args) {
//创建Semaphore,设置许可数量
Semaphore semaphore = new Semaphore(3);
for (int i = 1; i <= 6; i++) {
new Thread(()->{
try {
// 抢占
semaphore.acquire();//上锁
System.out.println(Thread.currentThread().getName()+"抢到了车位");
// 设置停车时间
TimeUnit.SECONDS.sleep(new Random().nextInt(5));
// 离开车位
System.out.println(Thread.currentThread().getName()+"------离开了车位");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//释放
semaphore.release();//解锁
}
},String.valueOf(i)).start();
}
}
}
输出结果如下:
2抢到了车位 1抢到了车位 3抢到了车位 2------离开了车位 4抢到了车位 4------离开了车位 5抢到了车位 3------离开了车位 6抢到了车位 1------离开了车位 5------离开了车位 6------离开了车位