0
点赞
收藏
分享

微信扫一扫

java多线程通信(互相唤醒,循环打印) wait,notify案例 以及虚假唤醒 可能出现的程序卡住问题

1.循环打印

public class OutWord {

private String word = "输出A";

public synchronized void outA() throws InterruptedException {
if (word.equals("B输出")){
this.wait();
}

//输出word
System.out.println("word = " + word);
word="B输出";
this.notify();
}

public synchronized void outB() throws InterruptedException {
if (word.equals("输出A")){
this.wait();
}

//输出word
System.out.println("word = " + word);
word="输出A";
this.notify();
}

}

public class Test {
public static void main(String[] args) {
OutWord outWord = new OutWord();

new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
outWord.outA();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"线程一").start();

new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
outWord.outB();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"线程二").start();
}
}

输出结果

word = 输出A
word = B输出
word = 输出A
word = B输出
word = 输出A
.........

2.虚假唤醒

2.1代码演示

加入我们增加两个线程 新增的线程分别是 打印A 和 打印B

public class Test {
public static void main(String[] args) {
OutWord outWord = new OutWord();

new Thread(()->{
for (int i = 0; i < 5; i++) {
try {
outWord.outA();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"线程一").start();

new Thread(()->{
for (int i = 0; i < 5; i++) {
try {
outWord.outB();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"线程二").start();

new Thread(()->{
for (int i = 0; i < 5; i++) {
try {
outWord.outA();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"线程三").start();

new Thread(()->{
for (int i = 0; i < 5; i++) {
try {
outWord.outB();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"线程四").start();
}
}

public class OutWord {

private String word = "输出A";

public synchronized void outA() throws InterruptedException {
if (word.equals("B输出")){
this.wait();
}

//输出word
System.out.println("word = " + word);
word="B输出";
this.notify();
}

public synchronized void outB() throws InterruptedException {
if (word.equals("输出A")){
this.wait();
}

//输出word
System.out.println("word = " + word);
word="输出A";
this.notify();
}

}

输出结果

word = 输出A
word = B输出
word = 输出A
word = B输出
word = 输出A
word = B输出
word = 输出A
word = B输出
word = 输出A
word = B输出
word = 输出A
word = B输出
word = B输出
word = B输出
word = B输出
word = B输出

2.2 什么是虚假唤醒

可以看到打印顺序已经乱了,出现了虚假唤醒 : 现在有四条线程执行打印任务 假设其中两条打印B的线程先后抢到锁,但是都不满足if条件,进入wait()等待,并释放了锁,此时打印A的线程拿到了锁,并且打印了A,随机唤醒了打印B的一条线程,线程打印B后又唤醒了另外一条打印B的线程,此时就会出现打印乱序的情况了 原因:notify随机唤醒一条线程,被唤醒的线程将会继续执行wait后的代码

2.2.3 解决办法

将 if条件换成 while 线程被唤醒后依然要进行条件判断 如果不满足,继续wait 释放锁,等待被唤醒

public class OutWord {

private String word = "输出A";

public synchronized void outA() throws InterruptedException {
// System.out.println(Thread.currentThread().getName()+"拿到了锁");
while (word.equals("B输出")){
// System.out.println(Thread.currentThread().getName()+"等待被唤醒");
this.wait();
// System.out.println(Thread.currentThread().getName()+"被唤醒,继续运行");
}
//输出word
System.out.println("word = " + word);
word="B输出";
//System.out.println(Thread.currentThread().getName()+"随机唤醒一条线程");
this.notify();
// System.out.println(Thread.currentThread().getName()+"执行完毕");
}

public synchronized void outB() throws InterruptedException {
// System.out.println(Thread.currentThread().getName()+"拿到了锁");
while (word.equals("输出A")){
// System.out.println(Thread.currentThread().getName()+"等待被唤醒");
this.wait();
// System.out.println(Thread.currentThread().getName()+"被唤醒,继续运行");
}

//输出word
System.out.println("word = " + word);
word="输出A";
// System.out.println(Thread.currentThread().getName()+"随机唤醒一条线程");
this.notify();
// System.out.println(Thread.currentThread().getName()+"执行完毕");
}

}

输出结果

word = 输出A
word = B输出
word = 输出A
word = B输出
word = 输出A
word = B输出
word = 输出A
word = B输出
word = 输出A
word = B输出
word = 输出A
word = B输出
word = 输出A
word = B输出
word = 输出A
word = B输出
word = 输出A
word = B输出
word = 输出A
word = B输出

打印顺序已经恢复正常,那是不是就没有其它问题了呢? 我们多运行几次 发现输出台居然卡住了 是死锁了吗

image-20220226130432248

3.解决虚假唤醒问题后出现的程序卡死问题

首先我们分析 锁的都是同一个对象 wait会释放锁,被唤醒后也需要重新竞争锁对象

死锁的四个条件 除了互斥 其他三个都不满足 所以不可能死锁

而代码中,只使用了 while循环 是while的原因吗?

 while(条件){
this.wait()
}

下一贴详细说明问题出现的原因 欢迎留言说下你的答案

举报

相关推荐

0 条评论