
package com.nanjing.juc;
//第一步 创建资源类,定义属性和操作方法
class Share{
//初始值
private int number = 0;
//+1的方法
public synchronized void add() throws InterruptedException {
//第二步 判断 干活 通知
if(number != 0){
//判断number的值是否是0,如果不是0,等待
this.wait();
}
//如果number是0,+1
number++;
System.out.println(Thread.currentThread().getName()+" ===== "+number);
//通知其他的线程
this.notifyAll();
}
//-1的方法
public synchronized void delete() throws InterruptedException {
//判断
if(number != 1){
this.wait();
}
//干活
number--;
System.out.println(Thread.currentThread().getName()+" ===== "+number);
//通知其他的线程
this.notifyAll();
}
}
public class ThreadDemo_04 {
public static void main(String[] args) {
//第三步 创建多个线程,调用资源类的操作方法
Share share = new Share();
new Thread(()->{
for (int i = 0; i < 30; i++) {
try {
share.add();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"刘德华").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
try {
share.delete();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"张学友").start();
}
}

虚假唤醒问题
package com.nanjing.juc;
//第一步 创建资源类,定义属性和操作方法
class Share{
//初始值
private int number = 0;
//+1的方法
public synchronized void add() throws InterruptedException {
//第二步 判断 干活 通知
if(number != 0){
//判断number的值是否是0,如果不是0,等待
this.wait();
}
//如果number是0,+1
number++;
System.out.println(Thread.currentThread().getName()+" ===== "+number);
//通知其他的线程
this.notifyAll();
}
//-1的方法
public synchronized void delete() throws InterruptedException {
//判断
if(number != 1){
this.wait();
}
//干活
number--;
System.out.println(Thread.currentThread().getName()+" ===== "+number);
//通知其他的线程
this.notifyAll();
}
}
public class ThreadDemo_04 {
public static void main(String[] args) {
//第三步 创建多个线程,调用资源类的操作方法
Share share = new Share();
new Thread(()->{
for (int i = 0; i < 30; i++) {
try {
share.add();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"刘德华").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
try {
share.delete();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"张学友").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
try {
share.add();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"黎明").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
try {
share.delete();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"郭富城").start();
}
}
出现匪夷所思的现象

查看JDK:


this.wait()方法有个特点,在哪里睡就在哪里醒
if(number != 0)只会判断一次
用while(number != 0) 不管你什么时候睡什么时候醒,都要经过while循环判断
修改代码后:
package com.nanjing.juc;
//第一步 创建资源类,定义属性和操作方法
class Share{
//初始值
private int number = 0;
//+1的方法
public synchronized void add() throws InterruptedException {
//第二步 判断 干活 通知
while(number != 0){
//判断number的值是否是0,如果不是0,等待
this.wait();
}
//如果number是0,+1
number++;
System.out.println(Thread.currentThread().getName()+" ===== "+number);
//通知其他的线程
this.notifyAll();
}
//-1的方法
public synchronized void delete() throws InterruptedException {
//判断
while(number != 1){
this.wait();
}
//干活
number--;
System.out.println(Thread.currentThread().getName()+" ===== "+number);
//通知其他的线程
this.notifyAll();
}
}
public class ThreadDemo_04 {
public static void main(String[] args) {
//第三步 创建多个线程,调用资源类的操作方法
Share share = new Share();
new Thread(()->{
for (int i = 0; i < 30; i++) {
try {
share.add();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"刘德华").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
try {
share.delete();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"张学友").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
try {
share.add();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"黎明").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
try {
share.delete();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"郭富城").start();
}
}

该博客探讨了在Java中使用`synchronized`关键字进行线程同步时可能出现的虚假唤醒问题,并通过代码示例展示了如何使用`wait()`和`notifyAll()`方法进行线程间的通信。作者指出了在条件判断中使用`if`语句可能导致的不正确唤醒,并建议改用`while`循环来确保线程安全。此外,还提到了多线程环境下可能遇到的死锁现象,强调了线程同步的重要性。
2185

被折叠的 条评论
为什么被折叠?



