CountDownLatch

类似计数器,倒数到0,门闩打开,否则一直await阻塞。如下:线程1和线程2,线程1必须等线程2打印完,才能打印;线程2打印完,调用latch.countdown(),计数器减一。 初始化参数,看业务倒数几次。
关键方法:
latch.await();
latch.countDown();

  1. public static void main(String[] args) {
  2. CountDownLatch latch = new CountDownLatch(1);
  3. char[] c1 = new char[]{'1','2','3','4','5'};
  4. char[] c2 = new char[]{'A','B','C','D','E'};
  5. new Thread(()->{
  6. try {
  7. latch.await();
  8. } catch (InterruptedException e) {
  9. e.printStackTrace();
  10. }
  11. System.out.println(Arrays.toString(c1));
  12. },"t1").start();
  13. new Thread(()->{
  14. System.out.println(Arrays.toString(c2));
  15. latch.countDown();
  16. },"t2").start();
  17. }

CyclicBarrier

循环栅栏,当定义的线程都完成了某种操作,栅栏才打开,只要有一个线程没跑完,栅栏也不会打开。new CyclicBarrier的第1个参数是参与的线程个数,第2个参数是所有线程都完成后下一步需要做的任务。
区别CountDownLatch:
① CountDownLatch 是一次性的,CyclicBarrier 是可循环利用的;
② CountDownLatch 参与的线程的职责是不一样的,有的在倒计时,有的在等待倒计时结束。CyclicBarrier 参与的线程职责是一样的。

  1. public static void main(String[] args) {
  2. CyclicBarrier barrier = new CyclicBarrier(5, ()->{
  3. System.out.println("完成最后的任务");
  4. });
  5. for (int i = 0; i < 5; i++) {
  6. int tempInt = i;
  7. new Thread(()->{
  8. try {
  9. System.out.println("线程 "+ tempInt +" 抵达战场");
  10. barrier.await();
  11. System.out.println("线程 " + tempInt +" 结束");
  12. } catch (Exception e) {
  13. e.printStackTrace();
  14. }
  15. }).start();
  16. }
  17. }

image.png

Semaphore

信号量,只是控制访问某些资源的线程数量,注意:只是控制线程个数,它不能保证线程安全哦。

  1. public static void main(String[] args){
  2. Semaphore semaphore = new Semaphore(3); //模拟3个车位
  3. for(int i=1;i<=6;i++){ //模拟6部车
  4. new Thread(()->{
  5. try{
  6. semaphore.acquire();
  7. System.out.println(Thread.currentThread().getName()+"\t抢到车位");
  8. try{
  9. TimeUnit.SECONDS.sleep(3);
  10. } catch (InterruptedException e) {e.printStackTrace();}
  11. System.out.println(Thread.currentThread().getName()+"\t停车3秒后离开车位");
  12. } catch (InterruptedException e){
  13. e.printStackTrace();
  14. } finally {
  15. semaphore.release();
  16. }
  17. },String.valueOf(i)).start();
  18. }
  19. }

image.png

LockSupport

它是用于创建锁和其他同步类的基本线程阻塞原语,它的构造方法是私有,不可以实例化。简言之就是:当调用park方法就阻塞住当前线程,当调用unPark方法,就把传入的线程唤醒 。

  1. /**
  2. * @title: LockSupport
  3. * @description: 交替输出1A2B3C
  4. * @author: l
  5. * @date: 2021/08/04 19:18
  6. */
  7. public class T_04TestLockSupport {
  8. static Thread t1 = null;
  9. static Thread t2 = null;
  10. public static void main(String[] args) {
  11. char[] c1 = "12345".toCharArray();
  12. char[] c2 = "ABCDE".toCharArray();
  13. t1 = new Thread(()->{
  14. for (char c : c1){
  15. System.out.println(c);
  16. LockSupport.unpark(t2);
  17. LockSupport.park();
  18. }
  19. });
  20. t2 = new Thread(()->{
  21. for (char c : c2){
  22. LockSupport.park();
  23. System.out.println(c);
  24. LockSupport.unpark(t1);
  25. }
  26. });
  27. t1.start();
  28. t2.start();
  29. }
  30. }