在上一次https://www.cnblogs.com/webor2006/p/11422587.html中通过实践来解了一个案例,先来回顾一下习题:

编写一个多线程程序,实现这样的一个目标:

1、存在一个对象,该对象有一个int类型的成员变量counter,该成员变量的初始值为0。

2、创建两个线程,其中一个线程对该对象的成员变量counter增1,另一个线程对该对象的成员变量减1。

3、输出该对象成员变量counter每次变化后的值。

4、最终输出的结果应为:101010101010。。。。

具体实现的代码就不回顾了,在上次的文末提到了这么一句:

下面来验证一下这个“完美”,目前这个程序只有一个线程去增,另一个线程去减,那。。如果对于增和减对应多个线程又会如何呢?下面改造一下:

看下结果是否依然如预期:

很明显一开始输出就不对了,另外!!

那。。为啥呢?两个线程就妥妥的,升级一下线程数就出问题,其实在以前https://www.cnblogs.com/webor2006/p/8419565.html的这篇博文中也专门学习过,这里再回忆捋一下:

现有是有两个增加线程和两个减少线程,假如目前有一个增加线程执行了增加方法,此时的counter++=1,如下:

接着用来减少的线程执行减少操作了,由于counter目前是1,所以可以正常执行到减操作,所以counter--=0:

好,第三个线程还是减少的线程又来执行减少操作了,而由于此时的counter=0,所以这个减少线程会进行wait(),如下:

接着还剩的一个减少线程又来执行减少操作了,此时由于counter还是等于0,那。。由于wait()是会将当前对象的锁给释放的,所有减小的两个线程此时都处于wait()状态了。

好接下来增加的一个线程来了,执行增加操作,由于减少的两个线程都处于wait()状态都不会持有对象的锁了,所以这个增加线程肯定是能正常执行增加操作的,目前count就会由0变为1了,如下:

接着注意重点来了:

好,正在wait()的两个减少的线程其中一个被唤醒了,所以接下来该线程就会将count--=0,如下:

好,重点又来了:

那么,最后一个wait()的减小线程又执行了一次counter--=-1:

所以结果就已经出问题了,其中需要特别注意的是:

也就是说:

回归到这个程序的问题上来,其实本质是由于:

所以,咱们来改一下程序:

好,咱们再运行一下:

一切正常了,而且可以看到程序也正常可以退出来。这也如官方文档所说:

其中还有一个原因需要注意:“spurious wakeups”,假唤醒,如果不放循环中肯定也会出问题。

Java精通并发-多线程同步关系实例剖析与详解的更多相关文章

  1. java多线程同步以及线程间通信详解&消费者生产者模式&死锁&Thread.join()(多线程编程之二)

    本篇我们将讨论以下知识点: 1.线程同步问题的产生 什么是线程同步问题,我们先来看一段卖票系统的代码,然后再分析这个问题: package com.zejian.test; /** * @author ...

  2. “全栈2019”Java多线程第十八章:同步代码块双重判断详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  3. Java多线程编程中Future模式的详解

    Java多线程编程中,常用的多线程设计模式包括:Future模式.Master-Worker模式.Guarded Suspeionsion模式.不变模式和生产者-消费者模式等.这篇文章主要讲述Futu ...

  4. Java多线程编程中Future模式的详解<转>

    Java多线程编程中,常用的多线程设计模式包括:Future模式.Master-Worker模式.Guarded Suspeionsion模式.不变模式和生产者-消费者模式等.这篇文章主要讲述Futu ...

  5. Java和Ibatis调用存储过程并取得返回值详解

    Java和Ibatis调用存储过程并取得返回值详解 2011-07-19 17:33 jiandanfeng2 CSDN博客 字号:T | T 本文主要介绍了Java和Ibatis调用存储过程的方法, ...

  6. “全栈2019”Java异常第二十二章:try-with-resources语句详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...

  7. “全栈2019”Java异常第十五章:异常链详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...

  8. “全栈2019”Java异常第十章:throw与throws区别详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...

  9. “全栈2019”Java第九十六章:抽象局部内部类详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

随机推荐

  1. [LeetCode] 213. House Robber II 打家劫舍 II

    Note: This is an extension of House Robber. After robbing those houses on that street, the thief has ...

  2. 【C/C++开发】TinyXml操作(含源码下载)

    前言 TinyXML是一个开源的解析XML的解析库,能够用于C++,能够在Windows或Linux中编译,使用TinyXML进行C++ XML解析,使用简单,容易上手. 这个解析库的模型通过解析XM ...

  3. k8s 修改节点角色和删除节点

    修改节点角色: kubectl label nodes cn-thin05 node-role.kubernetes.io/node= 卸载节点: kubectl drain jupiter --de ...

  4. C++ 把数组数据存入 CSV 文件,以及读取 CSV 文件的数据

    1. CSV-百度百科 2. 代码 #pragma once //Microsoft Visual Studio 2015 Enterprise #include<iostream> #i ...

  5. python基础 — Queue 队列

    queue介绍 queue是python中的标准库,俗称队列. 在python中,多个线程之间的数据是共享的,多个线程进行数据交换的时候,不能够保证数据的安全性和一致性,所以当多个线程需要进行数据交换 ...

  6. 关于类视图选择继承APIView还是工具视图(ListAPIView、CreateAPIView等等)

    APIView使用方法,直接继承APIView,get或者post请求.方法很简单1.先获取到要操作的数据,然后把数据放到serializer中序列化或者反序列化,最后return返回值(记得.dat ...

  7. 【IDEA使用技巧】(2) —— 模板设置

    1.IntelliJ IDEA模板使用 1.1.IDEA Live Templates的使用 选择File—Settings,在Editor中选择Live Templates,即可查看现有对所有语言的 ...

  8. Android--Facebook Login with LoginButton

    1.Layout文件添加Facebook的LoginBurtton <com.facebook.widget.LoginButton android:id="@+id/authButt ...

  9. spring boot 拦截 以及Filter和interceptor 、Aspect区别

    一.通过Filter这个大家很熟悉了吧,这是java规范的一个过滤器,他会拦截请求.在springboot中一般有两种配置方式.这种过滤器拦截并不知道你用的是哪一个Controller处理也不知道你用 ...

  10. Pycharm配置文档教程

    1 桌面找到快捷方式 双击打开 2 3 4 需要自行注册 5 看自己喜欢选择 喜欢白色 选择左边 喜欢黑色 选择右边 6 7 可选 如果你对 Markdown 感兴趣:或者会用 就点击 install ...