Java内存模型深度揭秘:多线程并发真相难以可控
【摘要】 多年来,Java并发编程一直是一个让开发者头疼不已的问题。无论使用哪种编程模型,线程安全问题总会随时出现。而我们之所以难以掌握多线程并发的真相,很大一部分原因就是因为Java内存模型(JMM)的存在。JMM定义了Java线程如何访问共享变量,以及变量值的传播规则。这对我们理解线程安全至关重要。本文将带你深入剖析JMM的工作原理,揭开它给并发编程带来的影响。这对你理解并控制多线程程序的行为将很...
多年来,Java并发编程一直是一个让开发者头疼不已的问题。无论使用哪种编程模型,线程安全问题总会随时出现。而我们之所以难以掌握多线程并发的真相,很大一部分原因就是因为Java内存模型(JMM)的存在。
JMM定义了Java线程如何访问共享变量,以及变量值的传播规则。这对我们理解线程安全至关重要。本文将带你深入剖析JMM的工作原理,揭开它给并发编程带来的影响。这对你理解并控制多线程程序的行为将很有帮助。
首先,我们来回顾一下单线程程序中变量值的传播:
int x = 0;
x = 3;
int y = x;
在单线程环境中,我们期望的结果是y的值为3。但在多线程环境中,情况就不一定了。
这是因为JVM允许重排序指令,以提高性能。例如,一个线程修改变量x的值,另一个线程可能首先读取变量y,而非x,导致看到的结果不一致。
JMM通过 Happen-Before 原则来约束指令重排序:
- 程序顺序规则:一个线程内,按照程序顺序进行的操作,后面操作的结果对前面可见
- 监视器锁规则:对一个共享变量的写与对这个变量的监视器锁的解锁具有Happens-Before关系
- volatile变量规则:对一个volatile变量的写与后续读/写该变量的线程间形成Happens-Before关系
- 线程开始规则:Thread对象的start()方法的调用与线程内首次访问特定变量的 Happens-Before关系
- 线程中断规则:对线程interrupt()方法的调用与被中断线程检测interrupt状态的Happens-Before关系
- 线程终止规则:线程中最后一个指令的完成与线程结束的Happens-Before关系
这些规则限制了指令重排序,保证了一个线程修改变量值后,其他线程可以看到最新值。
但是,规则也不能消除所有并发问题。一个典型案例:
int x = 0, y = 0;
thread1(){
x = 1;
y = 1;
}
thread2(){
if(x==1)
System.out.println("x equals 1");
if(y==1)
System.out.println("y equals 1");
}
这里x=1和y=1语句没有同步控制,线程2打印结果顺序不确定。这时我们就需要同步控制来保证程序顺序:
synchronized(this){
x = 1;
y = 1;
}
所以,理解JMM的Happen-Before原则,并掌握如何使用同步控制来保证程序顺序,这对我们正确编写线程安全程序至关重要。
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)