Java精通并发-多线程同步关系实例剖析与详解
在上一次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精通并发-多线程同步关系实例剖析与详解的更多相关文章
- java多线程同步以及线程间通信详解&消费者生产者模式&死锁&Thread.join()(多线程编程之二)
本篇我们将讨论以下知识点: 1.线程同步问题的产生 什么是线程同步问题,我们先来看一段卖票系统的代码,然后再分析这个问题: package com.zejian.test; /** * @author ...
- “全栈2019”Java多线程第十八章:同步代码块双重判断详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- Java多线程编程中Future模式的详解
Java多线程编程中,常用的多线程设计模式包括:Future模式.Master-Worker模式.Guarded Suspeionsion模式.不变模式和生产者-消费者模式等.这篇文章主要讲述Futu ...
- Java多线程编程中Future模式的详解<转>
Java多线程编程中,常用的多线程设计模式包括:Future模式.Master-Worker模式.Guarded Suspeionsion模式.不变模式和生产者-消费者模式等.这篇文章主要讲述Futu ...
- Java和Ibatis调用存储过程并取得返回值详解
Java和Ibatis调用存储过程并取得返回值详解 2011-07-19 17:33 jiandanfeng2 CSDN博客 字号:T | T 本文主要介绍了Java和Ibatis调用存储过程的方法, ...
- “全栈2019”Java异常第二十二章:try-with-resources语句详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...
- “全栈2019”Java异常第十五章:异常链详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...
- “全栈2019”Java异常第十章:throw与throws区别详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...
- “全栈2019”Java第九十六章:抽象局部内部类详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
随机推荐
- [LeetCode] 271. Encode and Decode Strings 加码解码字符串
Design an algorithm to encode a list of strings to a string. The encoded string is then sent over th ...
- 【SSH进阶之路】Spring的AOP逐层深入——采用注解完成AOP(七)
上篇博文[SSH进阶之路]Spring的AOP逐层深入——AOP的基本原理(六),我们介绍了AOP的基本原理,以及5种通知的类型, AOP的两种配置方式:XML配置和Aspectj注解方式. 这篇我们 ...
- GitLab - 安装并启动GitLab
1 - GitLab安装 1.1 信息确认 [Anliven@node102 ~]$ uname -a Linux node102 3.10.0-957.el7.x86_64 #1 SMP Thu N ...
- CentOS的vsftp修改默认配置路径方法
修改ftp的根目录只要修改/etc/vsftpd/vsftpd.conf文件即可: 加入如下几行: local_root=/var/www/htmlchroot_local_user=YESanon_ ...
- Oracle Spatial分区应用研究之二:按县分区与按省分区对比测试报告
1.实验目的 在上一轮的实验中,oracle 11g r2版本下,在87县市实验数据的基础上,比较了分表与分区的效率,得出了分区+全局索引效率较高的结论(见上一篇博客).不过我们尚未比较过不同的分区粒 ...
- POJ 1941 The Sierpinski Fractal
总时间限制: 1000ms 内存限制: 65536kB 描述 Consider a regular triangular area, divide it into four equal triangl ...
- 修改mysql自增字段的方法
修改mysql自增字段的方法 修改 test_user 库 user 表 auto_increment为 10000(从10000开始递增) <pre>mysql> alter ta ...
- 移动测(APP)试与web端测试的区别
1.操作环境不同 移动端的测试环境是安卓操作环境或者iOS操作系统: web端操作环境一般是windows(如果你用的是MC电脑,那就是iOS操作系统). 2.页面的显示尺寸不同 移动端的尺寸比较多, ...
- spring项目配置双数据源读写分离
我们最早做新项目的时候一直想做数据库的读写分离与主从同步,由于一些原因一直没有去做这个事情,这次我们需要配置双数据源的起因是因为我们做了一个新项目用了另一个数据库,需要把这个数据库的数据显示到原来的后 ...
- fwrite & fread 的使用
每一次切换文件操作模式必须调用fclose关闭文件. 如果直接切换操作模式,文件将损坏(出现乱码)或操作失败. 在调用了fclose时,作为参数的文件指针将被回收,必须再次定义,因此最好将功能封装. ...