当前位置:网站首页>synchronized下的 i+=2 和 i++ i++执行结果居然不一样
synchronized下的 i+=2 和 i++ i++执行结果居然不一样
2022-06-13 01:59:00 【李自提】
优质资源分享
| 学习路线指引(点击解锁) | 知识定位 | 人群定位 |
|---|---|---|
| 🧡 Python实战微信订餐小程序 🧡 | 进阶级 | 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。 |
| Python量化交易实战 | 入门级 | 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统 |
起因
逛【博客园-博问】时发现了一段有意思的问题:
问题链接:https://q.cnblogs.com/q/140032/
这段代码是这样的:
java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class AutomicityTest implements Runnable {
private int i = 0;
public int getValue() {
return i;
}
/**
* 同步方法,加2
*/
public synchronized void evenIncrement() {
i += 2;
// i++;
// i++;
}
@Override
public void run() {
while (true) {
evenIncrement();
}
}
public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPool();
// AutomicityTest线程
AutomicityTest automicityTest = new AutomicityTest();
exec.execute(automicityTest);
// main线程
while (true) {
int value = automicityTest.getValue();
if (value % 2 != 0) {
System.out.println(value);
System.exit(0);
}
}
}
}
代码很简单(一开始我没看清楚问题,还建议楼主去学习下Java语法,尴尬的一批~~~)
简单说明下代码逻辑
一、AutomicityTest类实现了Runnable接口,并实现 run() 方法,run() 方法中有一个 while(true) 循环,循环体中调用了一个 synchronized 修饰的方法 evenIncrement();
二、AutomicityTest类中有一个 int i 成员变量;
三、在 main() 方法中使用线程池执行线程(直接 new Thread().start() 是一样的),然后 while(true) 循环体中不停打印成员变量 i 的值,如果是奇数就退出虚拟机。
大家觉得这段代码会输出什么呢?
没错就是死循环!!!
有意思的地方来了,如果我把同步方法 evenIncrement() 改为下面这样:
java
public synchronized void evenIncrement() {
// i += 2;
i++;
i++;
}
执行结果是退出了虚拟机!!!
是不是很纳闷儿,要是不纳闷儿,就不用往下看了 >_<
一起来分析一下
1.首先从方法入口开始,main() 方法当中创建了一个AutomicityTest线程 和 本身 main() 所在的main线程,所以AutomicityTest线程是一个写线程,main线程是一个读线程,既然有读有写,又是多个线程,就涉及到工作内存和主存模型,在这里我就不赘述了。
2.写线程是有synchronized修饰的,但是读线程并没有,这就导致了读写不一致,解决方法就是给 getValue() 加上synchronized,此时执行结果就正常了
3.但是问题还没完,为什么 i += 2 死循环,而 【两条】 i++ 却退出了虚拟机呢?
字节码层面分析
java
public synchronized void evenIncrement() {
i += 2;
}
// 对应的字节码
public synchronized void evenIncrement();
descriptor: ()V
flags: ACC\_PUBLIC, ACC\_SYNCHRONIZED
Code:
stack=3, locals=1, args\_size=1
0: aload\_0
1: dup
2: getfield #2 // Field i:I
5: iconst\_2
6: iadd
7: putfield #2 // Field i:I
10: return
java
public synchronized void evenIncrement() {
i++;
i++;
}
// 对应的字节码
public synchronized void evenIncrement();
descriptor: ()V
flags: ACC\_PUBLIC, ACC\_SYNCHRONIZED
Code:
stack=3, locals=1, args\_size=1
0: aload\_0
1: dup
2: getfield #2 // Field i:I
5: iconst\_1
6: iadd
7: putfield #2 // Field i:I
10: aload\_0
11: dup
12: getfield #2 // Field i:I
15: iconst\_1
16: iadd
17: putfield #2 // Field i:I
20: return
i+=2;
字节码指令只有一段putfield,没有执行是偶数,执行了也是偶数,所以会死循环。
i++; i++;
字节码指令有两段putfield,由于之前getValue()没有加synchronized,那么在执行getValue()的时候,putfield可能没有执行,可能执行了一次,也可能执行了两次,没有执行是偶数,执行一次是奇数,执行两次是偶数;又因为AutomicityTest线程 run() 是 while (true) {} 的,所以它总能执行到奇数,退出虚拟机。
最后
到此就分析完了,所以该问题的关键就是写操作是原子的,但是读操作不是,导致读出来的数据不是最终的。
__EOF__
- **本文作者:** [Yu Shi xin](https://blog.csdn.net/biggbang)
- 本文链接:https://blog.csdn.net/yushixin1024/p/16368639.html
- 关于博主: 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志。
- 版权声明: 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在明显位置给出原文连接,否则保留追究法律责任的权利。
- 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角**【[推荐](javascript:void(0)】**一下。
边栏推荐
- pringboot之restfull接口规范注解(二)
- Opencv camera calibration (1): internal and external parameters, distortion coefficient calibration and 3D point to 2D image projection
- Get started quickly cmake
- [arithmetic, relation, logic, bit, compound assignment, self increasing, self decreasing and other] operators (learning note 4 -- C language operators)
- How to solve practical problems through audience positioning?
- [the second day of actual combat of smart lock project based on stm32f401ret6 in 10 days] (lighting with library function and register respectively)
- [the fourth day of actual combat of stm32f401ret6 smart lock project in 10 days] voice control is realized by externally interrupted keys
- Introduction to Google unit testing tools GTEST and gmoke
- Pyflink implements custom sourcefunction
- Répertoire d'exclusion du transport rsync
猜你喜欢

dfs与bfs解决宝岛探险

Server installation jupyterab and remote login configuration

In addition to the full screen without holes under the screen, the Red Devils 7 series also has these black technologies

Devaxpress Chinese description --tcxpropertiesstore (property store recovery control)

服务器安装jupyterlab以及远程登录配置

Jeux de plombiers

Day 1 of the 10 day smart lock project (understand the SCM stm32f401ret6 and C language foundation)

Developer contributions amd Xilinx Chinese Forum sharing - wisdom of questioning

Implementation of pointer linked list

Magics 23.0 how to activate and use the slice preview function of the view tool page
随机推荐
Decoding iFLYTEK open platform 2.0 is a fertile land for developers and a source of industrial innovation
Introduction to Google unit testing tools GTEST and gmoke
Decompression and compression of chrome resource file Pak
Why is Huawei matebook x Pro 2022 leading a "laptop" revolution
Compiling minicom-2.7.1 under msys2
Developer contributions amd Xilinx Chinese Forum sharing - wisdom of questioning
dfs与bfs解决宝岛探险
Répertoire d'exclusion du transport rsync
白噪声的详细理解
Topic creation and running example of ROS
rsync 传输排除目录
Luzhengyao, who has entered the prefabricated vegetable track, still needs to stop being impatient
5、 Improvement of inventory query function
Opencv camera calibration (1): internal and external parameters, distortion coefficient calibration and 3D point to 2D image projection
Using atexit to realize automatic destruct of singleton mode
万字讲清 synchronized 和 ReentrantLock 实现并发中的锁
Use of Arduino series pressure sensors and detected data displayed by OLED (detailed tutorial)
Interruption of 51 single chip microcomputer learning notes (external interruption, timer interruption, interrupt nesting)
传感器:SHT30温湿度传感器检测环境温湿度实验(底部附代码)
SWD debugging mode of stm32