前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >volatile的双重锁实现单例理解

volatile的双重锁实现单例理解

作者头像
逆回十六夜
修改2019-10-08 11:17:04
8440
修改2019-10-08 11:17:04
举报
文章被收录于专栏:逆回十六夜逆回十六夜

加锁有两种方式,一种是sychronized的重量级锁,一种是volatile,相比更为轻量级

先来看看具体的代码编写:

代码语言:javascript
复制
public class Singleton {
    private volatile static Singleton single = null;
    public static Singleton getSingleTest() {
        if (single == null) {
            synchronized (Single.class) {
                if (single == null) {
                    single = new Singleton ();
                }
            }
        }
        return single;
    }
}

volatile和sychronized结合的原因:volatile禁止编译器自作聪明的优化

  1. 编译器的优化分为很多方面,其中,多线程的使用中,如果不存在对某个变量的修改,而这个变量的参数是传入的情况下,那么就会将这个参数放置到工作内存中去,以避免每次都从主内存中读取,也就是存在将主内存刷到工作内存的情况,static也不例外。
  2. 禁止指令重排
  3. 禁止其他的编译器的优化操作(我知道的不多)

  • 内存方面的优化
线程一般使用的是各自的工作内存,而Java的线程操作因为都是对工作内存的处理(将主内存的东西复制到工作内存),对主内存的数据的变更会产生延迟,而volatile则会对工作内存的变量修改立刻回写到主内存,并且,对变量读取也是从主内存而不是工作内存。
线程一般使用的是各自的工作内存,而Java的线程操作因为都是对工作内存的处理(将主内存的东西复制到工作内存),对主内存的数据的变更会产生延迟,而volatile则会对工作内存的变量修改立刻回写到主内存,并且,对变量读取也是从主内存而不是工作内存。
  • 禁止指令重排

重排序是指编译器和处理器为了优化程序性能而对指令序列进行排序的一种手段。重排序需要遵守一定规则:

 a.重排序操作不会对存在数据依赖关系的操作进行重排序。

b.重排序是为了优化性能,但是不管怎么重排序,单线程下程序的执行结果不能被改变

  比如:a=1;b=2;c=a+b这三个操作,第一步(a=1)和第二步(b=2)由于不存在数据依赖关系, 所以可能会发

生重排序,但是c=a+b这个操作是不会被重排序的,因为需要保证最终的结果一定是c=a+b=3。

重排序在单线程下一定能保证结果的正确性,但是在多线程环境下,可能发生重排序,影响结果.

  • 禁止其他的编译器的优化操作(我知道的不多)

情况1测试代码

使用样例:

代码语言:javascript
复制
public class Test {
    private static int num = 0;
    public static void main(String[] args) throws InterruptedException {
        new Thread(()->{
            while(num==0){

            }
        }).start();

        Thread.sleep(1000);
        num = 1;
    }
}
代码语言:javascript
复制
public class Test {
    private volatile static int num = 0;
    public static void main(String[] args) throws InterruptedException {
        new Thread(()->{
            while(num==0){

            }
        }).start();

        Thread.sleep(1000);
        num = 1;
    }
}

这两段代码因为volatile而导致结果完全不同,第一段代码会一直运行而不结束,

而第二段的volatile中的num一直用的都是主内存,因而会及时的更新,因而能够在近乎1S的时间内很快结束运行。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • volatile和sychronized结合的原因:volatile禁止编译器自作聪明的优化
    • 情况1测试代码
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档