精通java多线程_Java精通并发-多线程同步关系实例剖析与详解

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

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

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

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

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

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

e541047d9883afddf5080735c99d7c6e.png

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

f642ef9ebe0e33158212923057fb2ec6.png

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

3908f2c26345fecac485057f2716a32f.gif

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

987a1c4d42846c2de14b242bac209ffd.png

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

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

eabf3cc0d900570da653b8f4f5c58ed3.png

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

7c5e187dafe8c9eb084a3ffa15c34b20.png

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

a83fb53d4f924374450b7932bf679ba2.png

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

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

b09bd04b16980749a5b0bbe99b49bc59.png

接着注意重点来了:

e0aa79f9b0efe7a365cc1b91cd4b68e3.png

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

1ffe8b20da46a81a194f07bd98c022ae.png

好,重点又来了:

2fec4bf51453423c0cfe1de945f8a7fb.png

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

40afc9bb39f51640d8e48a99167e9450.png

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

71eec63bad3c7a0727f616c2916ba270.png

也就是说:

b233db5c1744727c13977bcc2413e66b.png

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

de79fe400b786b5020d84232d59b9e5e.png

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

89eacaab272f7825a01a99e87474a53a.png

好,咱们再运行一下:

a732db666ff39e25eb02c6699d601c6c.png

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

bae06138a58d2c73aadaefd2a338d2a0.png

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值