业务需求
之前使用线程池时,更多的是关注执行的最终结果,至于每一个阶段到底是哪一个线程执行,其实我们并不关心,一般都是框架本身随机选取线程池;
现在有一个需求是交替循环打印,例如ABCABCABC......
解决方案
方案一
核心:synchronized关键字、Object类中的wait和notify方法
查看代码
/**
* 交替循环打印ABC 10次
* /
void contextLoads() {// 计数器private static int count = 0;// 锁private static final Object lock = new Object();Thread a = new Thread(() -> {for (int i = 1; i <= 10; i++) {// 申请获得锁synchronized (lock) {// 判断当前是否该打印// 特别强调:此处不能用if代替while!!!虽然当线程被唤醒时需要去重新获得锁,但代码是继续向下执行的,所以得循环while (count % 3 != 0) {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("第" + i + "次打印:" + "A");count++;// 唤醒所有正在等待的线程,最终只有一个线程能获得锁,其他线程继续等待lock.notifyAll();}}});Thread b = new Thread(() -> {for (int i = 0; i < 10; i++) {synchronized (lock) {while (count % 3 != 1) {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("B");count++;lock.notifyAll();}}});Thread c = new Thread(() -> {for (int i = 0; i < 10; i++) {synchronized (lock) {while (count % 3 != 2) {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("C");count++;lock.notifyAll();}}});// 启动线程a.start();b.start();c.start();
}
方案二
核心:
查看代码
void contextLoads() {/*** 阻塞线程被唤醒后需要重新获取锁,只有在拿到锁后才能从上次停止的地方继续执行*/private static int count = 0;private static final ReentrantLock lock = new ReentrantLock();Condition A = lock.newCondition();Condition B = lock.newCondition();Condition C = lock.newCondition();Thread a = new Thread(() -> {for (int i = 1; i <= 10; i++) {lock.lock();while (count % 3 != 0) {try {// 注意阻塞的主体A.await();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("第" + i + "次打印:" + "A");count++;// 注意唤醒的主体B.signal();lock.unlock();}});Thread b = new Thread(() -> {for (int i = 1; i <= 10; i++) {lock.lock();while (count % 3 != 1) {try {B.await();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("第" + i + "次打印:" + "B");count++;C.signal();lock.unlock();}});Thread c = new Thread(() -> {for (int i = 1; i <= 10; i++) {lock.lock();while (count % 3 != 2) {try {C.await();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("第" + i + "次打印:" + "C");count++;A.signal();lock.unlock();}});// 启动线程a.start();b.start();c.start();}
参考链接
【1】三个线程如何交替打印ABC循环100次