JUC系列之(二)volatile关键字
volatile关键字-内存可见性
引出内存可见性问题的示例:
package com.atguigu.juc;
public class TestVolatile {
public static void main(String[] args) {
// 线程threadDemo修改共享变量的值
ThreadDemo threadDemo = new ThreadDemo();
new Thread(threadDemo).start();
// main线程读取共享变量的值
while (true){
if (threadDemo.isFlag()){
System.out.println("------------------");
break;
}
}
}
}
class ThreadDemo implements Runnable {
private boolean flag = false;
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
flag = true;
System.out.println("flag=" + isFlag());
}
}
一直没有执行结束,像是main线程读取的共享变量的值一直都是false,导致main线程一直没有结束
内存可见性问题:
多个线程由于存在独立的缓存,因此在操作共享数据时彼此是不可见的(一个线程操作了共享变量之后,另一个线程看到的共享变量的状态还是改变之前的)
解决内存可见性问题:
通过同步锁可以解决内存可见性问题
package com.atguigu.juc;
public class TestVolatile {
public static void main(String[] args) {
// 线程threadDemo修改共享变量的值
ThreadDemo threadDemo = new ThreadDemo();
new Thread(threadDemo).start();
// main线程读取共享变量的值
while (true){
// 同步锁能够保证main线程每次都能刷新缓存,去主存中读数据,保证每次读到的共享数据都是最新的
synchronized (threadDemo) {
if (threadDemo.isFlag()){
System.out.println("------------------");
break;
}
}
}
}
}
class ThreadDemo implements Runnable {
private boolean flag = false;
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
flag = true;
System.out.println("flag=" + isFlag());
}
}
volatile关键字:既想解决内存可见性问题,又不想通过加同步锁的方式解决(加锁后效率极低),因此出现了该关键字
当多个线程进行操作共享数据时,可以保证内存中的数据可见。(一个线程操作了共享变量之后,另一个线程能够马上看到共享变量状态的变化)
使用了volatile关键字,就相当于线程1是直接改的主存中的共享变量,main线程是实时从主存中读取的共享变量的值。
volatile关键字原理:内存栅栏
volatile关键字造成性能下降的原因:被volatile关键字修饰后,不能再进行重排序了
package com.atguigu.juc;
public class TestVolatile {
public static void main(String[] args) {
// 线程threadDemo修改共享变量的值
ThreadDemo threadDemo = new ThreadDemo();
new Thread(threadDemo).start();
// main线程读取共享变量的值
while (true){
if (threadDemo.isFlag()){
System.out.println("------------------");
break;
}
}
}
}
class ThreadDemo implements Runnable {
// 使用volatile关键字修饰共享变量
private volatile boolean flag = false;
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
flag = true;
System.out.println("flag=" + isFlag());
}
}
解决了内存可见性问题就相当于各个线程在直接操作主存中的数据
volatile和synchronized的比较:
volatile仅仅是更轻量级的一种同步策略
volatile不具备“互斥性”
volatile不能保证变量的“原子性”
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构