一、线程间通信
线程间通信的模型有两种:共享内存和消息传递,以下方式都是基本这两种模型来实现的。我们来基本一道面试常见的题目来分析
场景—两个线程,一个线程对当前数值加 1,另一个线程对当前数值减 1,要求用线程间通信
1. synchronized 方案
class TestVolatile {
public static void main(String[] args) {
DemoClass demoClass = new DemoClass();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
demoClass.increment();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}, "线程A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
demoClass.decrement();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}, "线程B").start();
}
}
public class DemoClass {
private int number = 0;
public synchronized void increment() throws InterruptedException {
while (number != 0) {
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName() + "执行了加1操作,当前值为:" + number);
notifyAll();
}
public synchronized void decrement() throws InterruptedException {
while (number != 1) {
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName() + "执行了减1操作,当前值为:" + number);
notifyAll();
}
}
2. Lock 方案
class ShareNum {
private int number = 0;
private ReentrantLock lock = new ReentrantLock(true);
private Condition condition = lock.newCondition();
// ++操作
public void increase() {
// 上锁
lock.lock();
try {
while (number != 0) {
condition.await();
}
// 执行 ++ 操作
number++;
System.out.println(Thread.currentThread().getName() + "执行了 ++ 操作,当前number值为:" + number);
// 唤醒其它线程
condition.signalAll();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
// 解锁
lock.unlock();
}
}
// -- 操作
public void decrease() {
// 上锁
lock.lock();
try {
while (number != 1) {
condition.await();
}
// 执行 -- 操作
number--;
System.out.println(Thread.currentThread().getName() + "执行了 -- 操作,当前number值为:" + number);
// 唤醒其它线程
condition.signalAll();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
// 解锁
lock.unlock();
}
}
}
public class ConditionDemo {
public static void main(String[] args) {
ShareNum shareNum = new ShareNum();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
shareNum.increase();
}
}, "AA").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
shareNum.decrease();
}
}, "BB").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
shareNum.increase();
}
}, "CC").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
shareNum.decrease();
}
}, "DD").start();
}
}
二、线程间定制化通信
1. 案例介绍
A 线程打印 5 次 A,B 线程打印 10 次 B,C 线程打印 15 次 C,按照此顺序循环 10 轮
2. 实现过程
public class PrintTest {
// 线程通信标识:0-线程A 1-线程B 2-线程C
private int number = 0;
// 创建锁
private Lock lock = new ReentrantLock();
// 线程A的通信钥匙
private Condition conditionA =lock.newCondition();
// 线程B的通信钥匙
private Condition conditionB =lock.newCondition();
// 线程C的通信钥匙
private Condition conditionC =lock.newCondition();
/**
* 打印五次A
*/
public void printA(int round) {
try {
lock.lock();
while (number != 0) {
conditionA.await(); // 等待并释放锁
}
for (int i = 0; i < 5; i++) {
System.out.println("第 " + round + "轮:" + Thread.currentThread().getName() + "执行中,开始打印:=== A ===");
}
// 打印B
number = 1;
conditionB.signal();
} catch (Exception e) {
} finally {
lock.unlock();
}
}
/**
* 打印10次B
*/
public void printB(int round) {
try {
lock.lock();
while (number != 1) {
conditionB.await(); // 等待并释放锁
}
for (int i = 0; i < 10; i++) {
System.out.println("第 " + round + "轮:" + Thread.currentThread().getName() + "执行中,开始打印:=== B ===");
}
// 打印B
number = 2;
conditionC.signal();
} catch (Exception e) {
} finally {
lock.unlock();
}
}
/**
* 打印15次C
*/
public void printC(int round) {
try {
lock.lock();
while (number != 2) {
conditionC.await(); // 等待并释放锁
}
for (int i = 0; i < 15; i++) {
System.out.println("第 " + round + "轮:" + Thread.currentThread().getName() + "执行中,开始打印:=== C ===");
}
// 打印B
number = 0;
conditionA.signal();
} catch (Exception e) {
} finally {
lock.unlock();
}
}
}
class MainClass {
public static void main(String[] args) {
PrintTest printTest = new PrintTest();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
printTest.printA(i);
}
}, "线程A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
printTest.printB(i);
}
}, "线程B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
printTest.printC(i);
}
}, "线程C").start();
}
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 george_95@126.com