线程间通信
线程间通信的模型有两种:共享内存和消息传递,以下方式都是基本这两种模型来实现的。
场景:两个线程,一个线程对当前数值加1,另一个线程对当前数值减1,要求用线程间通信,两个线程交替进行.
多线程编程步骤:
- 第一步:创建资源类,在资源类中创建资源属性和操作方法
- 第二步: 在资源类操作方法中分为以下三步:
1. 判断
2. 干活
3. 通知- 第三步:创建多个线程,调用资源类的操作方法
- 第四步:防止虚假唤醒问题
synchronized 方案
//第一步 创建资源类,定义属性和方法
class Share {
//初始值
private int number = 0;
//+1的方法
public synchronized void incr() throws InterruptedException {
//第二步 判断 通知
while (number != 0) {//while防止虚假唤醒
//判断number值是否为0,如果不是0,等待
this.wait();
}
//如果number值是0,就+1操作 干活
number++;
System.out.println(Thread.currentThread().getName() + "::" + number);
//通知其他线程 通知
this.notifyAll();
}
//-1方法
public synchronized void decr() throws InterruptedException {
//第二步 判断
while(number != 1) {
//判断number值是否为0,如果不是0,等待
this.wait();
}
//如果number值是0,就-1操作 干活
number--;
System.out.println(Thread.currentThread().getName() + "::" + number);
//通知其他线程 通知
this.notifyAll();
}
}
public class ThreadDemo1 {
public static void main(String[] args) {
//第三步 创建多个线程,调用资源类的操作方法
Share share = new Share();
new Thread(() -> {
for(int i = 0; i< 10 ;i++) {
try {
share.decr();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
},"AA").start();
new Thread(() -> {
for(int i = 0; i< 10 ;i++) {
try {
share.incr();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
},"BB").start();
new Thread(() -> {
for(int i = 0; i< 10 ;i++) {
try {
share.decr();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
},"CC").start();
new Thread(() -> {
for(int i = 0; i< 10 ;i++) {
try {
share.incr();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
},"DD").start();
}
}
结果:
Lock 方案
newCondition()方法:
关键字 synchronized 与 wait()/notify()这两个方法一起使用可以实现等待/通知模式, Lock 锁的 newContition()方法返回 Condition 对象,Condition 类也可以实现等待/通知模式。
用 notify()通知时,JVM 会随机唤醒某个等待的线程, 使用 Condition 类可以进行选择性通知, Condition 比较常用的两个方法:
- await():会使当前线程等待,同时会释放锁,当其他线程调用 signal()时,线程会重新获得锁并继续执行。
- signal():用于唤醒一个等待的线程。
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//第一步 创建资源类,定义属性和操作方法
class Share {
private int number = 0;
//创建Lock
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
//+1
public void incr() throws InterruptedException {
//上锁
lock.lock();
try{
//第二步:判断,防止虚假唤醒
while(number != 0) {
condition.await();
}
//干活
number++;
System.out.println(Thread.currentThread().getName() + "::" + number);
//通知
condition.signalAll();
}finally {
lock.unlock();
}
}
//-1
public void decr() throws InterruptedException {
//上锁
lock.lock();
try{
//判断,干活,通知
while(number != 1) {
condition.await();
}
number--;
System.out.println(Thread.currentThread().getName() + "::" + number);
condition.signalAll();
}finally {
lock.unlock();
}
}
}
public class ThreadDemo2 {
public static void main(String[] args) {
//第三步 创建多个线程,调用资源类的操作方法
Share share = new Share();
new Thread(() -> {
for(int i = 0; i< 10 ;i++) {
try {
share.decr();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
},"AA").start();
new Thread(() -> {
for(int i = 0; i< 10 ;i++) {
try {
share.incr();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
},"BB").start();
new Thread(() -> {
for(int i = 0; i< 10 ;i++) {
try {
share.decr();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
},"CC").start();
new Thread(() -> {
for(int i = 0; i< 10 ;i++) {
try {
share.incr();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
},"DD").start();
}
}
线程间定制化通信
需求: A 线程打印 5 次 A,B 线程打印 10 次 B,C 线程打印 15 次 C,按照此顺序循环 10 轮
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//第一步 创建资源类
class ShareResource {
//定义标志位
private int flag = 1; // AA 1 BB 2 CC 3
//创建Lock锁
private Lock lock = new ReentrantLock();
private Condition c1 = lock.newCondition();
private Condition c2 = lock.newCondition();
private Condition c3 = lock.newCondition();
public void AA(int loop) throws InterruptedException {
lock.lock();
try{
while(flag != 1) {
c1.await();
}
System.out.println("第" + loop + "轮");
for (int i = 0; i < 5; i++) {
System.out.println("AA");
}
flag = 2;
c2.signal();
}finally {
lock.unlock();
}
}
public void BB(int loop) throws InterruptedException {
lock.lock();
try{
while(flag != 2) {
c2.await();
}
System.out.println("第" + loop + "轮");
for (int i = 0; i < 10; i++) {
System.out.println("BB");
}
flag = 3;
c3.signal();
}finally {
lock.unlock();
}
}
public void CC(int loop) throws InterruptedException {
lock.lock();
try{
while(flag != 3) {
c3.await();
}
System.out.println("第" + loop + "轮");
for (int i = 0; i < 15; i++) {
System.out.println("CC");
}
flag = 1;
c1.signal();
}finally {
lock.unlock();
}
}
}
public class ThreadDemo3 {
public static void main(String[] args) {
ShareResource shareResource = new ShareResource();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
shareResource.AA(i);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}).start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
shareResource.BB(i);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}).start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
shareResource.CC(i);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}).start();
}
}
结果: