一直搞不懂Java线程通信,这次终于明白了( 七 )

运行结果:

一直搞不懂Java线程通信,这次终于明白了

文章插图
使用Condition(条件变量)我们可以使用Condition精确唤醒下一个需要执行的线程
import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class HomeworkCondition {// 锁对象private static Lock lock = new ReentrantLock();// 阻塞队列private static Condition doWork = lock.newCondition();private static Condition checkWork = lock.newCondition();private static Condition recordWork = lock.newCondition();/*** 为什么要加这三个标识状态?* 如果没有状态标识,线程就无法正确唤醒,就一直处于等待状态*/private static Boolean t1Run = false;private static Boolean t2Run = false;private static Boolean t3Run = false;public static void main(String[] args) {// 布置作业线程Thread t1 = new Thread(() -> {lock.lock();try {System.out.println("......老师布置作业......");// t1执行完毕t1Run = true;// 唤醒doWork等待队列中的第一个线程doWork.signal();}finally {lock.unlock();}});// 学生写作业,需要等待老师布置完Thread t2 = new Thread(() -> {lock.lock();try {// 判断是否布置作业if(!t1Run) {// 还没布置作业,先不写作业,进入等待队列doWork.await();}System.out.println("......学生写作业......");t2Run = true;// 唤醒checkWork等待队列第一个线程checkWork.signal();} catch (InterruptedException e) {throw new RuntimeException(e);} finally {lock.unlock();}});// 老师家查作业,需要学生写完Thread t3 = new Thread(() -> {lock.lock();try {// 判断学生是否写完作业if(!t2Run) {// 没写完,先不检查,进入等待队列checkWork.await();}System.out.println("......老师检查作业......");t3Run = true;// 唤醒recordWork等待队列第一个线程recordWork.signal();} catch (InterruptedException e) {throw new RuntimeException(e);} finally {lock.unlock();}});// 老师上传作业情况,需要检查完Thread t4 = new Thread(() -> {lock.lock();try {if(!t3Run) {recordWork.await();}System.out.println("......老师记录作业情况......");} catch (InterruptedException e) {throw new RuntimeException(e);} finally {lock.unlock();}});t1.start();t2.start();t3.start();t4.start();}}使用CountDownLatch(倒计数)声明三个 CountDownLatch 计数器,初始只都为 1,每次执行上一部操作之后下一步操作的计数器 -1,当计数器值为0时就继续执行,否则就陷入等待
import java.util.concurrent.CountDownLatch;public class HomeworkCountDownLatch {public static void main(String[] args) {// 创建三个计数器CountDownLatch doWork = new CountDownLatch(1);CountDownLatch checkWork = new CountDownLatch(1);CountDownLatch recordWork = new CountDownLatch(1);// 布置作业线程Thread t1 = new Thread(() -> {System.out.println("......老师布置作业......");// 布置作业之后,做作业计数器 -1doWork.countDown();});// 学生写作业,需要等待老师布置完Thread t2 = new Thread(() -> {try {doWork.await();System.out.println("......学生写作业......");// 对 检查作业 -1checkWork.countDown();} catch (InterruptedException e) {throw new RuntimeException(e);}});// 学生写作业,需要等待老师布置完Thread t3 = new Thread(() -> {try {doWork.await();System.out.println("......老师检查作业......");// 对 录入作业情况 -1recordWork.countDown();} catch (InterruptedException e) {throw new RuntimeException(e);}});// 学生写作业,需要等待老师布置完Thread t4 = new Thread(() -> {try {recordWork.await();System.out.println("......老师记录作业情况......");} catch (InterruptedException e) {throw new RuntimeException(e);}});t1.start();t2.start();t3.start();t4.start();}}使用CyclicBarrier(回环栅栏)CyclicBarrier可以实现让一组线程等待至某个状态之后再全部同时执行,【回环】是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用,可以把这个状态当做barrier,当调用await()方法之后,线程就处于barrier了 。示例如下:
import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;public class HomeworkCyclicBarrier {public static void main(String[] args) {CyclicBarrier doWork = new CyclicBarrier(2);CyclicBarrier checkWork = new CyclicBarrier(2);CyclicBarrier recordWork = new CyclicBarrier(2);// 布置作业线程Thread t1 = new Thread(() -> {try {System.out.println("......老师布置作业......");//放开栅栏1doWork.await();} catch (BrokenBarrierException e) {throw new RuntimeException(e);} catch (InterruptedException e) {throw new RuntimeException(e);}});// 学生写作业,需要等待老师布置完Thread t2 = new Thread(() -> {try {//放开栅栏1doWork.await();System.out.println("......学生写作业......");//放开栅栏2checkWork.await();} catch (InterruptedException e) {throw new RuntimeException(e);} catch (BrokenBarrierException e) {throw new RuntimeException(e);}});// 学生写作业,需要等待老师布置完Thread t3 = new Thread(() -> {try {//放开栅栏2checkWork.await();System.out.println("......老师检查作业......");//放开栅栏3recordWork.await();} catch (InterruptedException e) {throw new RuntimeException(e);} catch (BrokenBarrierException e) {throw new RuntimeException(e);}});// 学生写作业,需要等待老师布置完Thread t4 = new Thread(() -> {try {//放开栅栏3recordWork.await();System.out.println("......老师记录作业情况......");} catch (InterruptedException e) {throw new RuntimeException(e);} catch (BrokenBarrierException e) {throw new RuntimeException(e);}});t1.start();t2.start();t3.start();t4.start();}}


推荐阅读