await():是当前线程等待直到锁向下计数为0,除非线程interrupted;
countDown():减少锁的数量,释放所有等待的线程。
CountDownLatch
主要有两个方法,当线程调用await()
时,此时线程会被阻塞;当线程调用countDown()
会将计数器减1(调用CountDown()
的线程不会阻塞)。
当计数器值变为0时,await()
阻塞的线程就会被唤醒,继续执行!
//期望输出:非主线程执行完毕后再执行主线程
public class CountDownLatchDemo {
public static void main(String[] args) {
for (int i = 1; i <=6; i++) {
new Thread(() ->{
System.out.println(Thread.currentThread().getName()+"\t号员工已下班打卡");
},String.valueOf(i)).start();
}
//主线程
System.out.println(Thread.currentThread().getName()+"\t锁门");
}
}
不符合要求!明显1-6号员工的线程没有执行完毕,主程序就提前执行了!
//枚举类
public enum EmployeeEnum {
ONE(1, "林大侠"),
TWO(2, "周大侠"),
THREE(3, "李大侠"),
FOUR(4, "猪大侠"),
FIVE(5, "乔大侠"),
SIX(6, "刘大侠");
private int code;
private String empName;
EmployeeEnum(int code, String empName) {
this.code = code;
this.empName = empName;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public static EmployeeEnum foreach_EmployeeEnum(int index) {
EmployeeEnum[] employee = EmployeeEnum.values();
for (EmployeeEnum employeeEnum : employee) {
if (employeeEnum.getCode() == index) {
return employeeEnum;
}
}
return null;
}
}
import com.lindaxia.gmall.jucdemo.jucdemo.enums.EmployeeEnum;
import java.util.concurrent.CountDownLatch;
/**
* 减少计数
*/
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
//初始化,指定计数器
CountDownLatch cd = new CountDownLatch(6);
for (int i = 1; i <=6; i++) {
new Thread(() ->{
System.out.println(Thread.currentThread().getName()+"\t员工已下班打卡");
cd.countDown(); //计数器减1,其它线程不阻塞
}, EmployeeEnum.foreach_EmployeeEnum(i).getEmpName()).start();
}
cd.await();////当前线程等待直到锁向下计数为0,才会被唤醒(放行)
//主线程
System.out.println(Thread.currentThread().getName()+"\t保安锁门");
}
}
符合期望输出!
CyclicBarrier
顾名思义可循环(Cyclic
)使用的屏障(Barrier
)。具体的功能如下:
让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。线程进入屏障通过CyclicBarrier
的await()
方法。
import java.util.concurrent.CyclicBarrier;
/**
* 循环屏障
*
* 集齐7颗龙珠召唤神龙、集五福
*/
public class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
System.out.println("集齐7颗龙珠召唤神龙!");
});
for (int i = 1; i <=7 ; i++) {
new Thread(()->{
try {
System.out.println(Thread.currentThread().getName()+"\t星龙珠被收集");
cyclicBarrier.await(); //阻塞线程
} catch (Exception e) {
e.printStackTrace();
}
},String.valueOf(i)).start();
}
}
}
在信号量上可定义两种操作:
acquire
(获取/抢占) 当一个线程调用acquire
操作时,它要么通过成功获取信号量(信号量减1),要么一直等下去,直到有线程释放信号量,或超时。
release
(释放)实际上会将信号量的值加1,然后唤醒等待的线程。
信号量主要用于两个目的,一个是用于多个共享资源的互斥使用,另一个用于并发线程数的控制。
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class SemaphoreDemo {
public static void main(String[] args) {
//3个停车位
Semaphore sp = new Semaphore(3);
//6俩轿车
for (int i = 1; i <=6 ; i++) {
new Thread(()->{
try {
sp.acquire();//抢占车位
System.out.println(Thread.currentThread().getName()+"\t号车驶入停车位!!!");
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+"\t号车离开停车位!!!");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
sp.release();//无论抢占是否成功,都要腾车位(释放资源)
}
},String.valueOf(i)).start();
}
}
}
☝上述分享来源个人总结,如果分享对您有帮忙,希望您积极转载;如果您有不同的见解,希望您积极留言,让我们一起探讨,您的鼓励将是我前进道路上一份助力,非常感谢!我会不定时更新相关技术动态,同时我也会不断完善自己,提升技术,希望与君同成长同进步!
☞本人博客:https://coding0110lin.blog.csdn.net/ 欢迎转载,一起技术交流吧!