CountDownLatch
CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能。比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了。
public class Test002 {public static void main(String[] args) throws InterruptedException {System.out.println("等待子线程执行完毕...");CountDownLatch countDownLatch = new CountDownLatch(2);new Thread(new Runnable() {@Overridepublic void run() {System.out.println("子线程," + Thread.currentThread().getName() + "开始执行...");countDownLatch.countDown();// 每次减去1System.out.println("子线程," + Thread.currentThread().getName() + "结束执行...");}}).start();new Thread(new Runnable() {@Overridepublic void run() {System.out.println("子线程," + Thread.currentThread().getName() + "开始执行...");countDownLatch.countDown();System.out.println("子线程," + Thread.currentThread().getName() + "结束执行...");}}).start();countDownLatch.await();// 调用当前方法主线程阻塞 countDown结果为0, 阻塞变为运行状态System.out.println("两个子线程执行完毕....");System.out.println("继续主线程执行..");}}
CyclicBarrier
CyclicBarrier初始化时规定一个数目,然后计算调用了CyclicBarrier.await()进入等待的线程数。当线程数达到了这个数目时,所有进入等待状态的线程被唤醒并继续。 CyclicBarrier就象它名字的意思一样,可看成是个障碍, 所有的线程必须到齐后才能一起通过这个障碍。CyclicBarrier初始时还可带一个Runnable的参数, 此Runnable任务在CyclicBarrier的数目达到后,所有其它线程被唤醒前被执行。
Semaphore
Semaphore是一种基于计数的信号量。它可以设定一个阈值,基于此,多个线程竞争获取许可信号,做自己的申请后归还,超过阈值后,线程申请许可信号将会被阻塞。Semaphore可以用来构建一些对象池,资源池之类的,比如数据库连接池,我们也可以创建计数为1的Semaphore,将其作为一种类似互斥锁的机制,这也叫二元信号量,表示两种互斥状态。它的用法如下:
availablePermits函数用来获取当前可用的资源数量
semaphore.acquire(); //申请资源
semaphore.release();// 释放资源
// 创建一个计数阈值为5的信号量对象 // 只能5个线程同时访问 Semaphore semp = new Semaphore(5); try { // 申请许可 semp.acquire(); try { // 业务逻辑 } catch (Exception e) { } finally { // 释放许可 semp.release(); } } catch (InterruptedException e) { }
案例:
需求: 一个厕所只有3个坑位,但是有10个人来上厕所,那怎么办?假设10的人的编号分别为1-10,并且1号先到厕所,10号最后到厕所。那么1-3号来的时候必然有可用坑位,顺利如厕,4号来的时候需要看看前面3人是否有人出来了,如果有人出来,进去,否则等待。同样的道理,4-10号也需要等待正在上厕所的人出来后才能进去,并且谁先进去这得看等待的人是否有素质,是否能遵守先来先上的规则。
代码:
class Parent implements Runnable {private String name;private Semaphore wc;public Parent(String name,Semaphore wc){this.name=name;this.wc=wc;}@Overridepublic void run() {try {// 剩下的资源(剩下的茅坑)int availablePermits = wc.availablePermits();if (availablePermits > 0) {System.out.println(name+"天助我也,终于有茅坑了...");} else {System.out.println(name+"怎么没有茅坑了...");}//申请茅坑 如果资源达到3次,就等待wc.acquire();System.out.println(name+"终于轮我上厕所了..爽啊");Thread.sleep(new Random().nextInt(1000)); // 模拟上厕所时间。System.out.println(name+"厕所上完了...");wc.release();} catch (Exception e) {}}
}
public class TestSemaphore02 {public static void main(String[] args) {// 一个厕所只有3个坑位,但是有10个人来上厕所,那怎么办?假设10的人的编号分别为1-10,并且1号先到厕所,10号最后到厕所。那么1-3号来的时候必然有可用坑位,顺利如厕,4号来的时候需要看看前面3人是否有人出来了,如果有人出来,进去,否则等待。同样的道理,4-10号也需要等待正在上厕所的人出来后才能进去,并且谁先进去这得看等待的人是否有素质,是否能遵守先来先上的规则。Semaphore semaphore = new Semaphore(3);for (int i = 1; i <=10; i++) {Parent parent = new Parent("第"+i+"个人,",semaphore);new Thread(parent).start();}}
}