关于多线程下的 volatile 一词的理解

关于多线程下的 volatile 一词的理解

1.首先我给出该关键词的俩方面用处,接下来展开详述。
作用:
1.1 在多线程访问下保证了线程之间的可见性。
1.2 被该关键词修饰的变量,限制了JVM的指令重排序的发生。

详述:
1.保证了线程之间的可见性
再多线程情况下,例如:多个线程对一资源进行访问时,如果某一个线程对该资源进行了读取,并修改,那么另外的线程不能马上发现该变量的改变。进而继续操作该变量。可能这些话有些难理解。那么接下来用一个例子来说明:
伪代码:

共100张票,同时2个窗口出售。
 class T3  implements Runnable{

   private static /*volatile */ int tick=100;
    @Override
    public void run() {
       while (tick>0){
           synchronized (this) {
           if (tick>0){
               System.out.println(Thread.currentThread().getName() + "卖出了第" + tick + "张票"); 

                   tick--;

           } else {
               System.out.println("票卖完了....");
           }
       }
       }
    }
     public static void main(String[] args) {
        t1  ---new Thread(new T3(),"第一个窗口").start();
        t2 ----new Thread(new T3(),"第二个窗口").start();
        }
        ```
       


在线程自身中,,有自己的独立运行内存区,它读到count=0值时,首先加载到自己内存中,做+1操作,相当与在自己内存中保存了一个副本,随后写入count=1。此时另外线程不能及时发现该变量值的变化。导致t2进来同样读到count=0值,也+1,此时出现了俩个相同的值被写入。
那么加上volatile 这个关键字,就相当与线程之间可以通信了,一个线程对资源的改变,另一个线程立马会察觉到。

2.被该关键词修饰的变量,限制了JVM的指令重排序的发生。

其实在jvm中,指令重排序问题一直都存在。
举个例子:
Object o=new Object();
对于如上操作,jvm内部其实是分为3步来进行的。
正常情况下指令:

               1.new Object ()的时候,首先申请存放该对象的内存空间。
               2.赋值操作。初始化对象。
               3.将该对象指向栈空间的引用变量 即  o  。

当在多线程情况下:可能会发生指令重排,

             1.new Object ()的时候,首先申请存放该对象的内存空间。
             3.将该对象指向栈空间的引用变量 即  o  。
             2.赋值操作。初始化对象。
             就变成1,3,2了,看下面的例子
    如果private /*volatile */ static SingleTonTest5 ss=null;不加关键字,会不会出现线程安全问题呢?答案是会的,他是线程不安全的。
public class SingleTonTest5 {

    //私有构造器(保证外部对象不能对其实例化)
     private SingleTonTest5(){

     }
     //创建一个实例化对象
     private /*volatile */ static SingleTonTest5 ss=null;

     //对外提供一个共有调用方法,用了关键字,保证了同一时间只有一个线程能进行访问,保证了线程安全
     public static SingleTonTest5 getInstance(){
         if (ss==null){               //双重检查机制
             synchronized (SingleTonTest5.class) {   //同步锁
                 if (ss == null) {
                     ss = new SingleTonTest5();
                 }
             }
         }
         return ss;
     }

当多个线程访问时,首先,到达if(ss==null) 第一次可能这里同时有俩个线程访问,发现都为空。那么接下来,因为有 synchronized (SingleTonTest5.class)同步锁的存在,只会有一个线程进来访问,发现对象为空,那么初始化对象。如果此时指令重排发生。会出现如果一个值如count=null;它会先申请内存空间,默认会赋一个0 的初始值。此时来没来得及初始化对象赋真正的值时,已经将该对象指向引用对象,那么接下来另外一个线程进来后,继续判断,一看不为空,那么直接返回。此时的到的对象值并不是真正赋值后的对象值。
那么加上关键字就会禁止指令重排序问题的发生。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值