CountDownLatch
让一些线程阻塞直到另一些线程完成一系列操作后才被唤醒。
该类主要的两个方法是await()、countDown()。调用await()的方法的线程会进入阻塞状态,其他调用countDown()方法,会使计数器减一,直到减为0,被阻塞的线程才会继续运行。
案例一
放学后需要一个人最后走负责锁门,那么这个人就需要等待其他同学都走后才会锁门。
不加CountDownLatch
package juc;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
for (int i = 1; i <= 6; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"\t 离开教室");
},i+"").start();
}
System.out.println(Thread.currentThread().getName()+"\t=========最后走");
}
}
可以看到这时会出问题,还没等到所有同学离开教室,main线程就已经走了。
加了CountDownLatch
package juc;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
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()+"\t 离开教室");
countDownLatch.countDown();
},i+"").start();
}
countDownLatch.await();
System.out.println(Thread.currentThread().getName()+"\t=========最后走");
}
}
结果正确。
案例二
秦灭六国。
package juc;
import jdk.nashorn.internal.objects.annotations.Getter;
public enum CountryEnum {
ONE(1,"齐"),TWO(2,"楚"),THREE(3,"燕"),FOUR(4,"赵"),FIVE(5,"魏"),SIX(6,"韩");
private Integer retCode;
private String retMessage;
CountryEnum(Integer retCode, String retMessage) {
this.retCode = retCode;
this.retMessage = retMessage;
}
public static CountryEnum forEach_CountryEnum(int index){
CountryEnum[] values = CountryEnum.values();
for (CountryEnum element : values) {
if(index == element.getRetCode()){
return element;
}
}
return null;
}
public Integer getRetCode() {
return retCode;
}
public void setRetCode(Integer retCode) {
this.retCode = retCode;
}
public String getRetMessage() {
return retMessage;
}
public void setRetMessage(String retMessage) {
this.retMessage = retMessage;
}
}
package juc;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
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()+"\t 国,被灭");
countDownLatch.countDown();
},CountryEnum.forEach_CountryEnum(i).getRetMessage()).start();
}
countDownLatch.await();
System.out.println(Thread.currentThread().getName()+"\t=========秦国一统华夏");
}
public static void closeDoor(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <= 6; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"\t 离开教室");
countDownLatch.countDown();
},i+"").start();
}
countDownLatch.await();
System.out.println(Thread.currentThread().getName()+"\t=========最后走");
}
}
CyclicBarrier
CyclicBarrier的字面意思是可循环的屏障。
主要作用是让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障时,才允许通过,所有被屏障拦截的线程才会继续运行。
案例
集齐7颗龙珠召唤神龙。
package juc;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.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++){
final int tempint = i;
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"\t 收集到第:"+tempint+"个龙珠");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
},String.valueOf(i)).start();
}
}
}
CyclicBarrier和CountDownLatch是相反的,一个是正计时,一个是倒计时。
Semaphore
信号量。
主要有两个目的,一个是用于多个共享资源的互斥使用,另一个用于并发线程数的控制。也就是说,线程使用时计数器会减1,不再使用会加1。
案例
抢车位。
package juc;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class SemaphoreDemo {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);
for (int i = 1; i <= 6; i++) {
new Thread(()->{
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+"\t抢到车位");
try{
TimeUnit.SECONDS.sleep(3);
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"\t离开车位");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
},i+"").start();
}
}
}