何为虚假唤醒:

当一个条件满足时,很多线程都被唤醒了,但是只有其中部分是有用的唤醒,其它的唤醒都是无用功;
比如买货:如果商品本来没有货物,突然进了一件商品,这是所有的线程都被唤醒了,但是只能一个人买,所以其他人都是假唤醒,获取不到对象的锁;

避免虚假唤醒:

Synchronized版,生产者和消费者问题

package com.jia.pc;

public class A {

    public static void main(String[] args) {

        Data data = new Data();

        new Thread(()->{
for (int i = 0; i < 10 ; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start(); new Thread(()->{
for (int i = 0; i < 10 ; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start(); new Thread(()->{
for (int i = 0; i < 10 ; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start(); new Thread(()->{
for (int i = 0; i < 10 ; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
} // 等待,业务,通知
class Data{ private int number = 0; // +1
public synchronized void increment() throws InterruptedException {
while (number != 0){
// 等待
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName() + "->" + number);
// 通知其他线程,我+1完毕
this.notifyAll();
} // -1
public synchronized void decrement() throws InterruptedException {
while (number == 0){
// 等待
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName() + "->" + number);
// 通知其他线程,我-1完毕
this.notifyAll();
}
}

运行结果:

A->1
B->0
A->1
B->0
A->1
B->0
A->1
B->0
A->1
B->0
A->1
B->0
A->1
B->0
A->1
B->0
A->1
B->0
A->1
B->0
C->1
D->0
C->1
D->0
C->1
D->0
C->1
D->0
C->1
D->0
C->1
D->0
C->1
D->0
C->1
D->0
C->1
D->0
C->1
D->0 Process finished with exit code 0

虚假幻想是如何产生的?

  把 while (number != 0) {}

  换成 if (number == 0) {}

  就会出现虚假唤醒。官方文档有标注;

为什么if判断会出现虚假唤醒?

  1. 因为if只会执行一次,执行完会接着向下执行if()外边的

  2. 而while不会,直到条件满足才会向下执行while()外边的

JUC版,生产者和消费者问题

使用 Condition 代码实现:

package com.jia.pc;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class C { public static void main(String[] args) { Data3 data = new Data3(); new Thread(()->{
for (int i = 0; i < 10 ; i++) {
data.printA();
}
},"A").start(); new Thread(()->{
for (int i = 0; i < 10 ; i++) {
data.printB();
}
},"B").start(); new Thread(()->{
for (int i = 0; i < 10 ; i++) {
data.printC();
}
},"C").start();
}
} // 资源类
class Data3{ private Lock lock = new ReentrantLock(); Condition conditionA = lock.newCondition();
Condition conditionB = lock.newCondition();
Condition conditionC = lock.newCondition(); private int number = 1; public void printA(){
lock.lock();
try {
while (number != 1){
//等待
conditionA.await();
}
System.out.println(Thread.currentThread().getName()+"->"+"AAAAA");
//唤醒执行的线程 B
number = 2;
conditionB.signal();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
} public void printB(){
lock.lock();
try {
while (number != 2){
//等待
conditionB.await();
}
System.out.println(Thread.currentThread().getName()+"->"+"BBBBB");
//唤醒 C
number = 3;
conditionC.signal();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
} public void printC(){
lock.lock();
try {
while (number != 3){
//等待
conditionC.await();
}
System.out.println(Thread.currentThread().getName()+"->"+"CCCCC");
//唤醒 A
number = 1;
conditionA.signal();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}

Condition:它可以精准的通知和唤醒线程;

 

最新文章

  1. iOS开发学习概述及知识整理
  2. Bootstrap之BootstrapDialog
  3. [转]SQL:JOIN用法
  4. linux 查看当前路径命令:pwd
  5. phpcms V9静态判断会员登录状态的方法
  6. MySQL数据库加密与解密
  7. 学习笔记_Java_day13_三层的HelloWorld程序(15)--不错,整体三层架构学习
  8. 娓娓道来c指针 (3)指针和数组
  9. 洛谷 1373 小a和uim之大逃离
  10. SQL整理5
  11. fieldset效果
  12. 使用Eclipse开始Java编程
  13. jsoup爬取图片到本地
  14. Electron 桌面应用打包(npm run build)简述(windows + mac)
  15. android ListView加载不同布局
  16. String painter HDU - 2476 -区间DP
  17. 【repost】JavaScript 基本语法
  18. 解决winscp中普通用户无法上传、删除、移动文件
  19. Bitmap用来做大数据处理
  20. [转]CMake cache

热门文章

  1. visual studio自动向量化
  2. 从Spring容器的角度理解Dubbo扩展点的加载时机
  3. 看SparkSql如何支撑企业数仓
  4. 面试突击24:为什么wait和notify必须放在synchronized中?
  5. 树莓派GPIO开发(二)RGB模块-PWM调节
  6. IDEA 端口占用,启动失败,提示Web server failed to start. Port 8080 was already in use.
  7. MYSQL时代是否将结束
  8. hacker模拟环境
  9. 自助BI工具是BI行业发展的趋势吗?
  10. C#操作WMI指南