volatile二三事1

来源:互联网 发布:网络在线客服的要求 编辑:程序博客网 时间:2024/06/07 04:00

1.主内存和工作内存

每个线程有自己的工作内存(线程栈),在调用主内存(公共内存)变量时,先将变量拷贝到工作内存,然后在私有内存中进行读写,而不是直接操作主内存中的数据。这样在多线程下就会有线程安全问题出现。

内存见的交互操作如下图,下面8个是原子操作(lock  unlock  read  load  use  agsin store write)当线程访问某一个对象时候值的时候,首先通过对象的引用找到对应在堆内存的变量的值,然后把堆内存变量的具体值load到线程本地内存中,建立一个变量副本,之后线程就不再和对象在堆内存变量值有任何关系,而是直接修改副本变量的值,在修改完之后的某一个时刻(线程退出之前),自动把线程变量副本的值回写到对象在堆中变量。



2.volatile的作用:强制从公共堆栈(主内存)中取得变量的值,而不是从工作内存(私有线程栈)中获得该变量的值

3.下面的例子

一旦运行在-server服务器模式中的64bit的JVM上回出现死循环,“线程停止了”永远不会输出,private boolean isRunning=true存储在线程栈和主内存中,在-server服务器模式下,为了线程效率,一直在线程栈中取得变量isRunning的值,而该值为true,而代码t.set(false)虽然被执行,但更新的却是主内存中的isRunning,所以-server模式下一直死循环。

也就是线程栈和主内存中的数据不一致导致的,解决办法是volatile,强制从主内存中取值

/**   * @Title: Run.java  * @Package volatile1  * @Description:volatile相关* @author LingLee * @date 2017年3月23日 下午4:23:53  * @version V1.0   */   package volatile1;class T1 extends Thread{private boolean isRunning=true;//存储在主内存和工作内存中public void run(){System.out.println("进入run了");while(isRunning){}System.out.println("线程被停止了");}public void set(boolean isRunning){this.isRunning=isRunning;}}/**    * @Title: Run    * @Description: TODO(用一句话描述该文件做什么)   */public class Run {public static void main(String[] args){try{T1 t1=new T1();t1.start();Thread.sleep(1000);t1.set(false);System.out.println("已经复制为FALSE");}catch(Exception e){e.printStackTrace();}}}
进入run了线程被停止了已经复制为FALSE

4.可见性(final synchronized volatile)

volatile的使用,jvm只保证了从主内存加载到线程栈中的值是最新的,当一个线程修改了变量的值,新值对于其他线程来说是可见性。如果volatile使用得当,会比synchronized的效率高,因为它不用进行线程见的上下文切换和线程调度,但是现在synchronized随着JDK的新版本,效率得到很大提升。


5.volatile和synchronized比较                                                                        

(1)volatile是轻量级同步实现,性能更好一些,但是volatile修饰的是变量,而synchronized修饰的是方法代码块

(2)多线程访问volatile变量不会阻塞,因为volatile在访问变量时都是从主内存中加载最新的值,而synchronized阻塞。

(3)volatile会保证可见性有序性但不保证原子性,synchronized保证可见性有序性也保证原子性,因为它维持了主内存和线程栈的数据同步。

(4)volatile和synchronized都保证了不可重排序

(5)volatile解决的是多线程间变量的可见性,而synchronized解决的是多线程访问资源的同步性


6、原子性、可见性、有序性

(1)volatile不具有原子性,synchronized和一些AtomicInteger原子类具有原子性

(2)volatile、final、synchronized具有可见性,当线程修改一个共享变量的值,其他线程能够看到。首先volatile每次修改变量都是刷新主内存中的值,并读取主内存的值。final是一旦完成初始化,就不可改变,所以对于其他线程也是可见的。

(3)volatile禁止指令重排序,在指令上添加很多内存屏障,而synchronized一个变量在同一时刻只允许一条线程拥有对象锁。所以具有的有序性,即线程内表现为串行的语义。


1 0
原创粉丝点击