在上一次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. redis密码配置

    配置密码 重启密码会失效 配置在redis.conf中 requirepass test123,则重启不会失效

  2. Linux系统下Redis单机版的安装详细教程

    Linux系统下Redis单机版的安装详细教程 1.下载软件安装包并上传到root目录 这里以旧版本的3.0进行安装,比较成熟稳定,具体软件可以通过qq群534073451文件下载

  3. 【C++札记】函数重载

    概述 函数重载指在相同作用域中多个函数名相同,函数的形参不同. 遵循规则: 1.函数名相同 2.函数的参数,类型,个数或顺序不一样都可以构成重载. 3.函数返回值得类型不同不构成重载,编译直接报错,存 ...

  4. FireDAC 中文字段过滤问题

    当使用 FireDAC Filter  过滤数据的时候,通常这样写: FDMemTable.Filtered := False; FDMemTable1.Filter := '姓名=' + strin ...

  5. Python中的int函数

    python帮组文档 class int(x, base=10) Return an integer object constructed from a number or string x, or ...

  6. 29 匿名内部类、函数型接口、lamda表达式的引入

    匿名内部类 参考:https://www.runoob.com/w3cnote/java-inner-class-intro.html 进入后搜索匿名内部类. 函数型接口 函数式接口(Function ...

  7. Winform 快速开发框架,上位机开发,工控机程序开发,CS程序开发

    1.当客户让你做个CS程序时,当你手上一穷二白,所有都要重复造轮,你是不是很烦. 2.但如果有一个通用的,快速开发框架,就可以把你从这些基础的工作解救出来,你专注做业务就好了. 3.本人其中一个项目的 ...

  8. 查看线程CPU利用率

    查看线程CPU利用率 方法1:利用ps命令查看对应的线程 1. ps -ef | grep 进程名称 2. ps -mp 进程ID -o THREAD,pid,tid,cmd,time,%cpu,%m ...

  9. Spark 系列(十二)—— Spark SQL JOIN 操作

    一. 数据准备 本文主要介绍 Spark SQL 的多表连接,需要预先准备测试数据.分别创建员工和部门的 Datafame,并注册为临时视图,代码如下: val spark = SparkSessio ...

  10. Centos7 在线安装开发环境 jdk1.8+mysql+tomcat

    写在最前 刚刚开始接触Linux,并折腾着在服务器上部署自己的项目,当然作为一个后端开发人员,必不可少的东西肯定是 JDK Mysql Tomcat容器 每天记录一天,每天进步一点点~~ 1.更新系统 ...