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] 298. Binary Tree Longest Consecutive Sequence 二叉树最长连续序列
Given a binary tree, find the length of the longest consecutive sequence path. The path refers to an ...
- Influx Sql系列教程五:insert 添加数据
接下来开始进入influxdb的curd篇,首先我们看一下如何添加数据,也就是insert的使用姿势 在进入本篇之前,对于不了解什么是retention policy, tag, field的同学,有 ...
- linux中vi编辑器没有颜色
vi是没有颜色的,vim是有颜色的.可是系统中没有安装vim. 我们可以通过 rpm -qa |grep vim 看看系统中是否安装了下面3个rpm包,如果有就是安装了vim. 点击(此处)折叠或打开 ...
- Apache Kafka + Spark Streaming Integration
1.目标 为了构建实时应用程序,Apache Kafka - Spark Streaming Integration是最佳组合.因此,在本文中,我们将详细了解Kafka中Spark Streamin ...
- hdu 2962 题解
题目 题意 给出一张图,每条道路有限高,给出车子的起点,终点,最高高度,问在保证高度尽可能高的情况下的最短路,如果不存在输出 $ cannot reach destination $ 跟前面 $ ...
- 魔术方法之__call、__callStatic
1.__call() 作用,当调用不存在的方法时,会调用该方法.实际应用,当程序调用不存在的方法时,意外导致程序终止. .或者当你调用了受保护的或者是私人的方法时,也会自动调用__call方法 结果: ...
- 小程序的组件插槽使用slot===以及小程序多个插槽使用方法 三步骤
===================== 小程序多个插槽使用方法 三步骤 小程序多个插槽第一步 小程序组件内使用多个插槽第二部 小程序使用多个插槽第三部
- [BZOJ2739]最远点(DP+分治+决策单调性)
根据旋转卡壳,当逆时针遍历点时,相应的最远点也逆时针转动,满足决策单调性.于是倍长成链,分治优化DP即可,复杂度O(n^2). #include<cstdio> #include<a ...
- WebApi接收接收日期格式参数时,日期类型(2019-10-08T16:00:00.000Z)后台接收时间少8小时问题
前端使用的是elementui的日期控件,将日期格式的数据提交到webapi后台时,接收到的日期格式少了8小时,这个原因是由于时区引起的,应该在WebApiConfig进行配置转成本地时间,解决少8小 ...
- vue watch 的简单使用
在项目开发中遇到的需求,这点写第一个dome 监听父组件传过来的值发送变化 在子组件中 <template> <div class="components"> ...