当前位置:网站首页>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)】**一下。
边栏推荐
- Why is Huawei matebook x Pro 2022 leading a "laptop" revolution
- 16 embedded C language interview questions (Classic)
- Plumber game
- Detailed explanation of C language conditional compilation
- What did Hello travel do right for 500million users in five years?
- General IP address, account and password of mobile IPv6 optical cat login, and mobile optical cat is in bridging mode
- Devaxpress Chinese description -- tdxgallerycontrol object (gallery component)
- 华为设备配置双反射器优化虚拟专用网骨干层
- 传感器:SHT30温湿度传感器检测环境温湿度实验(底部附代码)
- Use of Arduino series pressure sensors and detected data displayed by OLED (detailed tutorial)
猜你喜欢

What did Hello travel do right for 500million users in five years?
![[the fourth day of actual combat of stm32f401ret6 smart lock project in 10 days] voice control is realized by externally interrupted keys](/img/fc/f03c7dc4d5ee12aaa301f54e4cd3f4.jpg)
[the fourth day of actual combat of stm32f401ret6 smart lock project in 10 days] voice control is realized by externally interrupted keys

DFS and BFS to solve Treasure Island exploration

Vivo released originos ocean, and the domestic customized system is getting better and better

10 days based on stm32f401ret6 smart lock project practice day 1 (environment construction and new construction)

什么是立体角

Introduction to Google unit testing tools GTEST and gmoke

回顾ITIL各版本历程,找到企业运维发展的关键点

Ten thousand words make it clear that synchronized and reentrantlock implement locks in concurrency

微服务开发环境搭建
随机推荐
DFS and BFS to solve Treasure Island exploration
Cmake has no obvious error after compilation, but prompts that pthread cannot be found
General IP address, account and password of mobile IPv6 optical cat login, and mobile optical cat is in bridging mode
Decoding iFLYTEK open platform 2.0 is a fertile land for developers and a source of industrial innovation
蓝牙模块:使用问题集锦
Rsync transport exclusion directory
How to learn C language and share super detailed experience (learning note 1 -- basic data types of C language)
The first cell of devaxpress CXGRID after inserting a row is in focus editing status
反爬虫策略(ip代理、设置随机休眠时间、哔哩哔哩视频信息爬取、真实URL的获取、特殊字符的处理、时间戳的处理、多线程处理)
华为设备配置双反射器优化虚拟专用网骨干层
Devexpress implementation flow chart
万字讲清 synchronized 和 ReentrantLock 实现并发中的锁
Pyflink implements custom sourcefunction
Matplotlib drawing Chinese garbled code
Torch. Distributions. Normal
Combining strings and numbers using ssstream
3、 Upload fabric photos to SQL server and provide name to display fabric photos
CXGRID keeps the original display position after refreshing the data
Sensorless / inductive manufacturing of brushless motor drive board based on stm32
Can't use typedef yet? C language typedef detailed usage summary, a solution to your confusion. (learning note 2 -- typedef setting alias)