前言系列文章:【并发编程】知识脉络
上一篇文章了解了JMM:JMM是什么?_披甲上战场的博客-CSDN博客
文末提出了这种共享内存的工作模式有哪些隐患,这篇文章来分析。
核心问题更核心的问题是三种问题未必单独出现!(混合味果汁) 官网案例
- 可见性:如何保证某个线程的共享变量副本变化后其他线程可见?
- 有序性:如何保证共享变量副本的读写主内存按顺序执行?
- 原子性:如何保证某个线程的读写主内存完整执行?
- Chapter 8. Classes案例地址 Chapter 8. Classes
- 案例介绍:
class Test { static int i = 0, j = 0; static void one() { i++; j++; } static void two() { System.out.println("i=" + i + " j=" + j); } }使用方法:一个线程重复调用one(),另一个线程重复调用two()。
隐患现象:two()偶尔会输出一个大于i值的j值。
问题原因:因为示例中没有同步,i和j的共享值可能会被打乱顺序更新。
原因解释:
- 解决方案(一):同步方法Synchronized修饰方法
class Test { static int i = 0, j = 0; static synchronized void one() { i++; j++; } static synchronized void two() { System.out.println("i=" + i + " j=" + j); } }使用方法:在方法上用Synchronized修饰。
解决问题:
- 这可以防止one()和two()并发执行。
- 可以确保i和j的共享值在方法1返回之前都被更新。
图例解释:
- 解决方案(二):变量用volatile修饰
总结 1、能保证可见性的举手♂️?class Test { static volatile int i = 0, j = 0; static void one() { i++; j++; } static void two() { System.out.println("i=" + i + " j=" + j); } }使用方法:变量i和j用关键字volatile修饰
解决问题:
- 这允许one()和two()并发执行。
- 保证对i和j的共享值的访问发生的次数和顺序与每个线程在执行程序文本时发生的次数完全相同。
图例解释:
- volatile、synchronized、内存屏障、Lock、final举手了。
- volatile、synchronized、Lock举手了。
- synchronized、Lock、CAS举手了。
之后我们逐一拜访一下这些举手♂️的......
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)