Java多线程 — — lock、await 、signal 组合 替换 sync、wait、notifyAll,实现精准唤醒线程
接上篇博客我们使用老旧的多线程API实现了线程间通信,
但是为了让线程运行的更有效率,
本篇我们采用 lock、await 、signal 新特性,
进行再次酿造,
旧瓶子,装点新酒
需求:
很简单,要求顺次打印1次A,2次B,3次C,循环来10遍。
废话不多说,直接上源码:
package ldk.test; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @Author: ldk * @Date: 2020/12/18 16:03 * @Describe: */ public class ThreadTest1 { public static void main(String[] args) { Data data = new Data(); //生产者线程A new Thread(() -> { for (int i = 0; i < 10; i++) { try { data.print1(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "A").start(); //生产者线程B new Thread(() -> { for (int i = 0; i < 10; i++) { try { data.print2(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "B").start(); //消费者线程C new Thread(() -> { for (int i = 0; i < 10; i++) { try { data.print3(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "C").start(); } //数据类 static class Data { //表示数据个数 private int number = 1; private Lock lock = new ReentrantLock(); private Condition condition1 = lock.newCondition(); private Condition condition2 = lock.newCondition(); private Condition condition3 = lock.newCondition(); public void print1() throws InterruptedException { lock.lock(); try { while (number != 1) { condition1.await(); } System.out.println(Thread.currentThread().getName()); number = 2; condition2.signal(); } finally { lock.unlock(); } } public void print2() throws InterruptedException { lock.lock(); try { while (number != 2) { condition2.await(); } for (int i = 0; i < 2; i++) { System.out.println(Thread.currentThread().getName()); } number = 3; condition3.signal(); } finally { lock.unlock(); } } public void print3() throws InterruptedException { lock.lock(); try { while (number != 3) { condition3.await(); } for (int i = 0; i < 3; i++) { System.out.println(Thread.currentThread().getName()); } number = 1; condition1.signal(); } finally { lock.unlock(); } } } }
执行结果:
简单分析:
需求很明了,
按顺序走10遍,
我们主要优化的是精准唤醒,
每次执行完须定向地执行下个目标,
lock和unlock想必大家很熟悉,就是上锁,解锁操作,
主要是condition控制了线程的精准调度
流程简单分析:
1、值初始化为1,很自然进入print1,打印1次
2、值变成2,唤醒condition2,执行打印2次,唤醒condition3(即使开始是condition3抢到,现在值为2,condition3线程只能等待,最终还是有condition2执行)
3、此时值为3,且condition3唤醒,打印3次,值设置为1,唤醒condition1,
4、...周而复始,打印10遍为止。