目录
1. CountDownLatch
1.1 CountDownLatch介绍
CountDownLatch是一个同步工具类,用于协调多个线程之间的同步问题。 CountDownLatch能够使主线程在等待其他的线程完成各自业务后再继续向下执行。通过计数器进行监控。 计数器设置为需要等待的线程任务数。但一个线程执行完毕调用计数器减一。但计数器值为0时。表示所有任务的线程都执行完毕。主线程再继续执行。
1.2 CountDownLatch不足
CountDownLatch为一次性变量,计数器值只能通过构造方法初始化一次,故CountDownLatch不能重复使用。
1.3 代码演示
场景:到了中午A、B、C组队去饭堂吃饭,A要上一趟厕所;B还有一些手头的工作;C在搜索附近的饭店。A、B、C各有各的事情,但都约好了在门口集合一起去。
public class CountDownLatchTest {
private static int num = 3;
private static ExecutorService executor = Executors.newFixedThreadPool(num);
private static CountDownLatch countDownLatch = new CountDownLatch(num);
public static void main(String[] args) throws InterruptedException {
try {
System.out.println("12点午休开始.");
executor.execute(() -> {
try {
System.out.println("A去上厕所.");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
countDownLatch.countDown();
System.out.println("A上完厕所到门口等待.");
}
});
executor.execute(() -> {
try {
System.out.println("B处理手头的工作.");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
countDownLatch.countDown();
System.out.println("B完成手头的工作到门口等待.");
}
});
executor.execute(() -> {
try {
System.out.println("C搜索附近的饭店.");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
countDownLatch.countDown();
System.out.println("C确认饭店到门口等待.");
}
});
countDownLatch.await();
System.out.println("A、B、C一起去吃饭.");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
executor.shutdown();
}
}
}
2. CyclicBarrier
2.1 CyclicBarrier介绍
CyclicBarrier字面意思是“可重复使用的栅栏”,CyclicBarrir是ReentrantLock和Condition组合实现。 CyclicBarrier与CountDownLatch很像,区别是CyclicBarrier可重用。 CountDownLatch是基于AQS的共享模式实现,而CyclicBarrier是基于Condition实现。 CyclicBarrier内部存在一个计数器,当任务线程执行到屏障就调用await方法将阻塞,此时计数器减一。当计数器减为0时所有被阻塞的线程被唤醒。
2.2 代码演示
场景:到了中午A、B、C组队去饭堂吃饭,A要上一趟厕所;B还有一些手头的工作;C在搜索附近的饭店。A、B、C各有各的事情,但都约好了在门口集合一起去吃饭并各自点了喜爱菜。
public class CyclicBarrierTest {
private static int num = 3;
private static ExecutorService executor = Executors.newFixedThreadPool(num);
private static CyclicBarrier cyclicBarrier = new CyclicBarrier(num, () -> {
System.out.println("A、B、C一起去吃饭.");
});
public static void main(String[] args) {
try {
System.out.println("12点午休开始.");
executor.execute(() -> {
try {
System.out.println("A去上厕所.");
Thread.sleep(2000);
System.out.println("A上完厕所到门口等待.");
cyclicBarrier.await();
System.out.println("A点了“香菇滑鸡饭”.");
} catch (Exception e) {
e.printStackTrace();
}
});
executor.execute(() -> {
try {
System.out.println("B处理手头的工作.");
Thread.sleep(3000);
System.out.println("B完成手头的工作到门口等待.");
cyclicBarrier.await();
System.out.println("B点了“回锅肉饭”.");
} catch (Exception e) {
e.printStackTrace();
}
});
executor.execute(() -> {
try {
System.out.println("C搜索附近的饭店.");
Thread.sleep(1000);
System.out.println("C确认饭店到门口等待.");
cyclicBarrier.await();
System.out.println("C点了“红烧茄子饭”.");
} catch (Exception e) {
e.printStackTrace();
}
});
} catch (Exception e) {
e.printStackTrace();
} finally {
executor.shutdown();
}
}
}
3. Semaphore
3.1 Semaphore介绍
Semaphore 是基于信号量实现的同步,底层是基于AQS原理实现的,支持公平锁与非公平锁两种方式。 一般非公平锁的效率会高些,但可能会造成饥饿现象。默认非公平锁。
3.2 代码演示
场景:到了中午A、B、C组队去饭堂吃饭,A要上一趟厕所;B还有一些手头的工作;C在搜索附近的饭店。A、B、C各有各的事情,但都约好了在门口集合一起去。
public class SemaphoreTest {
private static int num = 3;
private static int initNum = 0;
private static ExecutorService executor = Executors.newFixedThreadPool(num);
private static Semaphore semaphore = new Semaphore(initNum);
public static void main(String[] args) throws InterruptedException {
try {
System.out.println("12点午休开始.");
executor.execute(() -> {
try {
System.out.println("A去上厕所.");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
System.out.println("A上完厕所到门口等待.");
}
});
executor.execute(() -> {
try {
System.out.println("B处理手头的工作.");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
System.out.println("B完成手头的工作到门口等待.");
}
});
executor.execute(() -> {
try {
System.out.println("C搜索附近的饭店.");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
System.out.println("C确认饭店到门口等待.");
}
});
semaphore.acquire(num);
System.out.println("A、B、C一起去吃饭.");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
executor.shutdown();
}
}
}