• 谈谈volatile


    volatile的作用:

      volatile关键字的作用包括:保障可见性,保障有序性。

    何为保障可见性,看下面的代码:

    package com.mashibing.thread.lock;
    
    public class TestVolatile {
        public static void main(String[] args) {
            try {
                Thread8 t = new Thread8();
                t.start();
                Thread.sleep(1000);
                t.setRunning(false);
                System.out.println("已赋值false");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    class Thread8 extends Thread {
        private boolean isRunning = true;
    
        public boolean isRunning() {
            return isRunning;
        }
    
        public void setRunning(boolean isRunning) {
            this.isRunning = isRunning;
        }
    
        public void run() {
            System.out.println("进入run()了");
            while (isRunning) {
            }
            System.out.println("线程被停止了");
        }
    }
    View Code

    我们在主线程里面,启动一个线程,然后去修改的isRunning属性,达到中止线程中while循环的目的,但是实际我们运行代码的结果如下:

     很明显,线程没有停止。此时我们在isRunning变量加上vo;alite关键字,结果如下:

     这就达到了我们的目的了。所以volatile可以保障一个线程修改了共享变量,能够对其他线程保持可见。

    何为保障有序性,看下面的代码:

    package singleton;
    
    /**
     * @ClassName SingletonDemo2
     * @Description 双重检查(比较完美的写法)
     * @Author liuyi
     * @Date 2020/6/7 13:23
     * @Version 1.0
     */
    public class SingletonDemo4 {
        //必须加volatile关键字,防止指令重排
        private static volatile SingletonDemo4 instance;
    
        private SingletonDemo4(){
    
        }
    
        public synchronized static SingletonDemo4 getInstance(){
            //为什么要进行双重检查
            //比如两个线程同时进入该方法,都拿到instance为空,其中一个拿到锁并new了一个实例,
            //此时另外一个线程它并不知道你已经new了实例,所以当它拿到锁之后会继续new一个实例
            //所以如果在锁里面继续判断一次是很有必须要的
            if(instance==null){
                synchronized (SingletonDemo4.class){
                    if(instance==null){
                        instance = new SingletonDemo4();
                    }
                }
            }
            return instance;
        }
    
        public static void main(String[] args) {
            for (int i = 0; i <100 ; i++) {
                new Thread(()->{
                    System.out.println(getInstance());
                }).start();
            }
        }
    }
    View Code

    这里是一个经典的单例模式实现方式之一,我们用volatile关键字单例对象,这里为什么加volatile关键字,就是为了防止出现指令重排序,保障有序性。

    我们来分析这里为什么需要防止出现指令重排序,

    synchronized (SingletonDemo4.class){
                    if(instance==null){
                        instance = new SingletonDemo4();
                    }
                }
    我们来看被锁住的这句代码,instance = new SingletonDemo4(),其实这句话在计算机底层是分为几个步骤实现的,那么就会一种情况,instance先被
    写入到共享变量,然后再被初始化。因为,计算机底层的执行顺序是可以重新排列的,这种现象被称作为指令重排序。那么刚好这个时候,有其他的线程走到if(instance==null)
    就会再次进行初始化,这就破环了单例。当然这种情况,只有在超高的并发下才可能出现,我们自己做测试很难出现。

      

  • 相关阅读:
    error C2146: 语法错误 : 缺少“;”
    字符串大小写格式化
    Click Button关键字——模拟单击页面中的按钮
    Get List Items关键字——获取页面中一个下拉列表中的所有下拉框选项
    Get Title关键字——获取浏览器网页的title
    Click Link关键字——模拟单击一个链接
    Get Text关键字——用来获取文本内容
    Input Text关键字——模拟向一个输入框中输入文字内容
    Open Browser、Close Browser关键字——打开和关闭浏览器
    Go Back关键字、Go To关键字——浏览器的后退、前进操作
  • 原文地址:https://www.cnblogs.com/liu-yi/p/13499438.html
Copyright © 2020-2023  润新知