volatile关键字及内存可见性
2024-10-19 20:34:42
先看一段代码:
package com.java.juc; public class TestVolatile { public static void main(String[] args) {
ThreadDemo td = new ThreadDemo();
new Thread(td).start();
while(true){
if(td.isFlag()){
System.out.println("----------------");
break;
}
}
} } class ThreadDemo implements Runnable{ private boolean flag = false;
public void run() {
try {
Thread.sleep(200);
flag = true;
System.out.println("flag= "+ isFlag());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* @return the flag
*/
public boolean isFlag() {
return flag;
}
/**
* @param flag the flag to set
*/
public void setFlag(boolean flag) {
this.flag = flag;
} }
运行这段代码,运行的结果只有:
flag= true
这是由于 子线程在操作共享数据时,会将主存总的flag,复制一份到线程的缓存中进行操作,操作完成后会再将数据写到主存中,由于while(true)是一个运行效率非常高的一句代码,而且运行速度非常快,导致主线程再执行循环时没有机会从主存中读取到数据,导致flag的值是主线程最初读到的值,flag = false;
在共享变量上加一个volatile关键字,会解决这个问题
package com.java.juc; public class TestVolatile { public static void main(String[] args) {
ThreadDemo td = new ThreadDemo();
new Thread(td).start();
while(true){
if(td.isFlag()){
System.out.println("----------------");
break;
}
}
} } class ThreadDemo implements Runnable{ private volatile boolean flag = false;
public void run() {
try {
Thread.sleep(200);
flag = true;
System.out.println("flag= "+ isFlag());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* @return the flag
*/
public boolean isFlag() {
return flag;
}
/**
* @param flag the flag to set
*/
public void setFlag(boolean flag) {
this.flag = flag;
} }
----------------
flag= true
volatile 关键字的作用:当多个线程操作共享数据时,可以保证内存中的数据是可见的。
可以使用内存再来解释,可以认为各个线程操作各自独立缓存中的数据是实时与主存进行同步的,可以理解为多个线程直接在主存中操作数据,而不是在各自的缓存中。
加了volatile后性能还是比什么都不加要讲的,但是比锁的效率要高。
加了volatile之后效率会低在哪?
实际上JVM底层有个优化,叫指令重排序,使用volatile修饰后就不能重排序了。
加锁的效率是最低的(使用synchronized关键字),同步锁会使线程每次从主存中读取数据,但是同步锁的效率很低。有多个线程来访问时先判断锁,如果被其他线程锁挡住,则线程会进入阻塞挂起状态,那得等到下次cpu再次分配任务,才能执行。
当然:volatile和synchronized还是不同的。volatile相较与synchronized是一种较为轻量级的同步策略。
注意:
1. volatile 不具备 "互斥性"
2. volatile 不能保证变量的 "原子性"
最新文章
- Bad Request - Request Too Long
- 引入math模块中的log()方法,导致";TypeError: return arrays must be of ArrayType";,什么原因?
- [LintCode] 3Sum 三数之和
- Win7精简成功后的总结
- Lintcode: Interval Sum
- 第九篇、CSS布局
- Android TextView自动实现省略号
- DataSnap
- HDOJ 1325 并查集
- hdu 1395 2^x mod n = 1 暴力过~~最好学下欧拉定理~~~
- UITableviewCell 重用内存
- macaca 初试
- xterm配置
- CPU的概念
- ARM驱动:SEC S3C2410X Test B/D USB驱动 安装
- 极致21点开发DAY1
- Spring 整合 RocketMQ
- bzoj千题计划268:bzoj3131: [Sdoi2013]淘金
- Qt5_加载DLL
- Linux Shell编程、变量、控制语句
热门文章
- Mycat实现Mysql数据库读写分离
- Android 使用OpenCV的三种方式(Android Studio)
- 一个不成熟的编程员,写写 js 的面向对象
- 【Head First Servlets and JSP】笔记4:HttpServletRequest req
- HAproxy 介绍
- RequestMapping请求映射方式
- Nuxt / Vue.js in TypeScript: Object literal may only specify known properties, but 'components' does not exist in type 'VueClass'
- mysql基础(4)-数据导入
- review03
- 本地的html服务