Volatile关键字

什么是Volatile

可见性也就是说一旦某个线程修改了该被volatile修饰的变量,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,可以立即获取修改之后的值。

在Java中为了加快程序的运行效率,对一些变量的操作通常是在该线程的寄存器或是CPU缓存上进行的,之后才会同步到主存中,而加了volatile修饰符的变量则是直接读写主存。

以后用到多线程全局共享时候 尽量加上哈~~

与synchronize结合使用会更好哦

废话不多说,来撸代码吧!

package com.toov5.threadSecurity;

class volitileDemo  extends Thread{
    public boolean flag = true;
    
    @Override
    public void run() {
        
        System.out.println("线程开始");
        while (flag) {
            
        }
        System.out.println("线程结束");
        
    }
    public void setRuning(boolean flag){
        this.flag=flag;
    }
}


public class ThreadVolitile {
    public static void main(String[] args) {
      volitileDemo volitileDemo =    new volitileDemo();
      volitileDemo.start();
      try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
      volitileDemo.setRuning(false); //主线程把状态修改后,按理说 上面线程执行的代码会退出掉
      System.out.println("falg已经为false");
      try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
      System.out.println(volitileDemo.flag);
      
    }
}

按理说三秒后主线程修改了flag的值,用户线程会退出,执行结束的

可以看到还是在运行的。

分析:

改这个值是主线程去改的 但是主内存的值还没有修改呀 没有刷新到主内存中

用户线程还不知道,一直用的本地的

原因:线程之间是不可见的,读取的是副本,没有及时读取到主内存结果。

解决办法使用Volatile关键字将解决线程之间可见性, 强制线程每次读取该值的时候都去“主内存”中取值

如何修改?

大名鼎鼎的volitile关键字上场!

package com.toov5.threadSecurity;

class volitileDemo  extends Thread{
    public volatile boolean flag = true;
    
    @Override
    public void run() {
        
        System.out.println("线程开始");
        while (flag) {
            
        }
        System.out.println("线程结束");
        
    }
    public void setRuning(boolean flag){
        this.flag=flag;
    }
}


public class ThreadVolitile {
    public static void main(String[] args) {
      volitileDemo volitileDemo =    new volitileDemo();
      volitileDemo.start();
      try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
      volitileDemo.setRuning(false); //主线程把状态修改后,按理说 上面线程执行的代码会退出掉
      System.out.println("falg已经为false");
      try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
      System.out.println(volitileDemo.flag);
      
    }
}

看结果:

 进展顺利!哈哈 看到了没 该技术时候就结束了

 当用Volatile关键字时候 很快就会刷新到主内存中去!

 保证了另一个线程的可见性,立即更新到主内存中去了!

volitile能保证可见性,不能保证原子性!相对于synchronize,volitile效率高,他直接修改值刷新到内存中!

只要是全局共享的变量,全部都加上volitile关键字。

 

Volatile特性

  1.保证此变量对所有的线程的可见性,这里的“可见性”,如本文开头所述,当一个线程修改了这个变量的值,volatile 保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。但普通变量做不到这点,普通变量的值在线程间传递均需要通过主内存(详见:Java内存模型)来完成。

  2.禁止指令重排序优化。有volatile修饰的变量,赋值后多执行了一个“load addl $0x0, (%esp)”操作,这个操作相当于一个内存屏障(指令重排序时不能把后面的指令重排序到内存屏障之前的位置),只有一个CPU访问内存时,并不需要内存屏障;(什么是指令重排序:是指CPU采用了允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理)。

volatile 性能:

  volatile 的读性能消耗与普通变量几乎相同,但是写操作稍慢,因为它需要在本地代码中插入许多内存屏障指令来保证处理器不发生乱序执行。

Volatile与Synchronized区别

(1)从而我们可以看出volatile虽然具有可见性但是并不能保证原子性。

(2)性能方面,synchronized关键字是防止多个线程同时执行一段代码,就会影响程序执行效率,而volatile关键字在某些情况下性能要优于synchronized。

但是要注意volatile关键字是无法替代synchronized关键字的,因为volatile关键字无法保证操作的原子性。

 

原文地址:https://www.cnblogs.com/toov5/p/9830486.html