何为虚假唤醒:

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

避免虚假唤醒:

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:它可以精准的通知和唤醒线程;

 

Java并发编程虚假唤醒问题(生产者和消费者关系)的更多相关文章

  1. JAVA并发框架之Semaphore实现生产者与消费者模型

    分类: Java技术      锁和信号量(Semaphore)是实现多线程同步的两种常用的手段.信号量需要初始化一个许可值,许可值可以大于0,也可以小于0,也可以等于0.      如果大于0,表示 ...

  2. Java并发编程之美之并发编程线程基础

    什么是线程 进程是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,线程则是进程的一个执行路径,一个进程至少有一个线程,进程的多个线程共享进程的资源. java启动main函数其实就 ...

  3. 【Java并发编程实战】----- AQS(三):阻塞、唤醒:LockSupport

    在上篇博客([Java并发编程实战]----- AQS(二):获取锁.释放锁)中提到,当一个线程加入到CLH队列中时,如果不是头节点是需要判断该节点是否需要挂起:在释放锁后,需要唤醒该线程的继任节点 ...

  4. Java 并发编程 生产者消费者模式

    本文部分摘自<Java 并发编程的艺术> 模式概述 在线程的世界里,生产者就是生产数据的线程,消费者就是消费数据的数据.生产者和消费者彼此之间不直接通信,而是通过阻塞队列进行通信,所以生产 ...

  5. java并发编程之美-阅读记录1

    1.1什么是线程? 在理解线程之前先要明白什么是进程,因为线程是进程中的一个实体.(线程是不会独立存在的) 进程:是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,线程则是进程中的 ...

  6. Java并发编程(您不知道的线程池操作), 最受欢迎的 8 位 Java 大师,Java并发包中的同步队列SynchronousQueue实现原理

    Java_并发编程培训 java并发程序设计教程 JUC Exchanger 一.概述 Exchanger 可以在对中对元素进行配对和交换的线程的同步点.每个线程将条目上的某个方法呈现给 exchan ...

  7. Java并发编程--基础进阶高级(完结)

    Java并发编程--基础进阶高级完整笔记. 这都不知道是第几次刷狂神的JUC并发编程了,从第一次的迷茫到现在比较清晰,算是个大进步了,之前JUC笔记不见了,重新做一套笔记. 参考链接:https:// ...

  8. JAVA并发编程J.U.C学习总结

    前言 学习了一段时间J.U.C,打算做个小结,个人感觉总结还是非常重要,要不然总感觉知识点零零散散的. 有错误也欢迎指正,大家共同进步: 另外,转载请注明链接,写篇文章不容易啊,http://www. ...

  9. Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition

    Java并发编程:线程间协作的两种方式:wait.notify.notifyAll和Condition 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者 ...

随机推荐

  1. Solution -「Gym 102979E」Expected Distance

    \(\mathcal{Description}\)   Link.   用给定的 \(\{a_{n-1}\},\{c_n\}\) 生成一棵含有 \(n\) 个点的树,其中 \(u\) 连向 \([1, ...

  2. 关于mybatis,需要掌握的基础

    目录 ❀ 总结 mybatis,需要掌握的基础如下: 1.了解ORM 思想.ORM思想的作用.映射配置的两种方式 2.MyBatis开发流程(基本使用) 3.日志框架 4.了解mybatis生命周期并 ...

  3. AFNetworking 修改

    相比大家刚刚拿到AFNetworking  post  和 get 请求数据的时候都会有些小问题吧 NSLocalizedDescription=Request failed: unacceptabl ...

  4. vscode使用vue代码模板

    1.vscode中打开:文件>首选项>用户片段>vue.json 2.复制下面代码并保存. 点击查看代码 { "Print to console": { &quo ...

  5. k8s初面考点ReplicaSet副本集极限9连击你懂了吗?

    k8s初面考点ReplicaSet副本集极限9连击你懂了吗? k8s考点灵魂拷问9连击 考点之简单描述一下k8s副本集ReplicaSet有什么作用? 考点之为什么ReplicaSet将取代Repli ...

  6. Smartbi与Tableau功能盘点,我选Smartbi!

    只要对大数据BI行业有所了解的人群,想必这两个数据分析工具Tableau和PowerBI都已经耳熟能详了吧. ·关于Tableau Tableau是一种数据可视化的工具,可提供复杂的计算.数据混合和仪 ...

  7. 缓冲区(buffer)与缓存(cache) 缓冲:缓解冲击,缓存:临时存储

    缓存与缓冲区 简要概述 缓存(cache):故名思意就是临时存储一下数据的存储器,其他设备可能等下还用的到数据.缓存区可以用来做缓冲区 缓冲区(Buffer):故名意思就是解决设备之间速度不匹配的问题 ...

  8. idea教程--快速插入依赖

    1.打开pom.xml文件,按下快捷键Alt+insert,弹出Generate框,选择Dependency. 2.搜索所需jar的关键字. 3.点击add.添加jar包成功.如果第二步没有所要jar ...

  9. 论文解读(GIN)《How Powerful are Graph Neural Networks》

    Paper Information Title:<How Powerful are Graph Neural Networks?>Authors:Keyulu Xu, Weihua Hu, ...

  10. pandas模块篇(之二)

    今日内容概要 布尔选择器 索引 数据对齐 数据操作(增出改查) 算术方法 DataFrame(Excel表格数据) 布尔选择器 import numpy as np import pandas as ...