接上篇博客我们使用老旧的多线程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遍为止。