volatile 关键字 内存可见性
引入:
一个线程flag值为true了,而另一个线程flag值为false,这是涉及到内存可见性问题
当运行程序时,JVM都会为每一个执行任务的线程分配一个独立的缓存。
当支线程对主存中的共享资源进行改变时,先会将共享资源读取到支线程的缓存中来,然后对flag值进行改变,再将flag值写到主存中。但在写之前main线程将共享资源读到main线程的缓存中,此时flag值为false;main线程读完以后,支线程flag值写回到主存中,然后执行打印语句flag is true。
但main线程中的flag值为false;main线程执行while(true)时,while(true)是调用底层代码执行效率高,没有机会对主存中的flag修改的值进行读取,就反复执行 flag值一直都是false。
这就是内存可见性问题,问题在于多个线程操作共享数据时,都有独立的缓存,对操作的数据彼此是不可见的。
使用同步锁能解决上述问题,但用同步锁效率非常的底,当有多个线程对此代码访问,一个线程持有demo锁,相应其它线程访问以判断有其它线程在占用demo这把锁,这个线程就阻塞挂起,下次等待CPU非配任务再来执行。
public static void main(String[] args) {
ThreadDemo demo = new ThreadDemo();
new Thread(demo).start(); //支线程
while(true){
synchronized (demo) {
if(demo.isFlag()){
System.out.println("如果flag为true,执行次语句");
break;
}
}
}
}
不想枷锁 但又有内存可见性问题 这时候使用 Volatile关键字 对共享资源加上volatile
volatile 关键字:当多线程进行操作共享数据时,可以保证内存中的数据可见
volatile调用计算机底层的代码 内存栅栏,时时刻刻缓存将修改的数据实时刷新到主存内中
比锁的效率要高 volatile效率低,低在JVM的优化,叫重排序,使用volatile关键字以后不能重排序
1.volatile相较于sychronized比,volatile是一种较为轻量级的同步策略。
2.volatile 不具备“互斥性” sychronized互斥性是一个线程持有锁,其它线程无法进来,当线程释放锁,其它线程才能执行
3.volatile 不能保证变量“原子性”
public class TestVolatile {
/* 一、Volatile 关键字:当多线程进行操作共享数据时,可以保证内存中的数据可见 */
public static void main(String[] args) {
ThreadDemo demo = new ThreadDemo();
new Thread(demo).start(); //支线程
while(true){
if(demo.isFlag()){
System.out.println("如果flag为true,执行次语句");
break;
}
}
}
}
// 旗帜flag原来为false 然后让线程sleep 150ms, 线程睡醒后将flag改为true
class ThreadDemo implements Runnable{
private volatile boolean flag = false;
public void run() {
synchronized (this) {
try {
Thread.sleep(150);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
System.out.println("flag is "+isFlag());
}
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}