Java内存模型
我们首先来介绍一下Java内存模型:
- JMM 即 Java Memory Model,它定义了主存、工作内存抽象概念,底层对应着 CPU 寄存器、缓存、硬件内存、 CPU 指令优化等。
JMM的主要作用如下:
- 计算机硬件底层的内存结构过于复杂
- JMM的意义在于避免程序员直接管理计算机底层内存,用一些关键字synchronized、volatile等可以方便的管理内存。
JMM主要体现在三个方面:
- 原子性 – 保证指令不会受到线程上下文切换的影响 (我们在管程已经介绍过了)
- 可见性 – 保证指令不会受 cpu 缓存的影响
- 有序性 – 保证指令不会受 cpu 指令并行优化的影响
可见性
这一小节我们来介绍可见性
可见性问题
首先我们根据一段代码来体验什么是可视性:
// 我们首先设置一个run运行条件设置为true,在线程t运行1s之后,我们在主线程修改run为false希望停下t线程
static boolean run = true;
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->{
while(run){
// ....
}
});
t.start();
sleep(1);
run = false;
}
// 线程t不会如预想的停下来!
我们进行简单的分析:
- 初始状态, t 线程刚开始从主内存读取了 run 的值到工作内存。
- 因为 t 线程要频繁从主内存中读取 run 的值,JIT 编译器会将 run 的值缓存至自己工作内存中的高速缓存中,减少对主存中 run 的访问,提高效率
- 1 秒之后,main 线程修改了 run 的值,并同步至主存,而 t 是从自己工作内存中的高速缓存中读取这个变量 的值,结果永远是旧值
可见性解决
我们提供两种可见性的解决方法:
- volatile(易变关键字)
// 它可以用来修饰成员变量和静态成员变量
// 他可以避免线程从自己的工作缓存中查找变量的值,必须到主存中获取它的值,线程操作 volatile 变量都是直接操作主存
// 我们首先设置一个run运行条件设置为true,在线程t运行1s之后,我们在主线程修改run为false希望停下t线程
static volatile boolean run = true;
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->{
while(run){
// ....
}
});
t.start();
sleep(1);
run = false;
}
// 这时程序会停止!
- synchronized(锁关键字)
// 我们对线程内容进行加锁处理,synchronized内部会自动封装对其主存进行查找
static Object obj = new Object();
static boolean run = true;
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->{
synchronized(obj){
while(run){
// ....
}
}
});
t.start();
sleep(1);
run = false;
}
// 这时程序会停止!
可见性解决方法对比
我们对volatile和synchronized两种方法进行简单对比:
- volatile只能保证可见性和有序性,synchronized可以保证可见性,有序性和原子性
- volatile属于轻量级操作,synchronized属于重量级操作;前者的各部分消耗量较少,性能较高
我们在这里介绍一下为什么synchronized能进行可见性问题解决:
本站声明:
1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/java/293050.html