设计模式 - 对于Java多线程synchronized(.class)和valatile的困惑?

 Candy王丫丫 发布于 2022-10-25 17:45

这是head first 设计模式中单例模式第182页的一段代码

public class Singleton {
    // 为什么要使用volatile关键字?
    private volatile static Singleton uniqueInstance;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (uniqueInstance == null) {
            /* 为什么要使用synchronized (Singleton.class),使用synchronized(this)或者
            synchronized(uniqueInstance)不行吗?而且synchronized(uniqueInstance)的效率更加高?*/
            synchronized (Singleton.class) {
                if (uniqueInstance == null) {
                    uniqueInstance = new Singleton();
                 }
            }
        }
        return uniqueInstance;
    }
}

问题一:为什么要使用volatierle关键字?
问题二:为什么要使用synchronized (Singleton.class),使用synchronized(this),或者synchronized(uniqueInstance)不行吗?而且synchronized(uniqueInstance)的效率更加高?


Stackoverflow上面的答案

对于问题一

public class Foo extends Thread {
  private volatile boolean close = false;
  public void run() {
    while(!close) {
      // do work
    }
  }
  public void close() {
    close = true;
    // interrupt here if needed
  }
}

you need volatile because the thread reading close in the while loop is different from the one that calls close(). Without volatile, the thread running the loop may never see the change to close.


对于问题二,作者并没有给出原因,只贴出了代码

static void myMethod() {
  synchronized(MyClass.class) {
    //code
  }
}
is equivalent to

static synchronized void myMethod() {
  //code
}
and

void myMethod() {
  synchronized(this) {
    //code
  }
}
is equivalent to

synchronized void myMethod() {
  //code
}
3 个回答
  • 关于问题一我再补充一点:
    上述答案其实都不太恰当,volatile在如上单例模式中起的作用其实并不是第一时间读到
    假设没有加volatile,第一时间读不到,那么它的值还是null(?), 在进去里面的synchronized时就会读到最新值(synchronized保证了原子性和可见性),看起来volatile可有可无。
    这里的volatile的语意是在JDK5后增强的,可以理解为原子的,如果不加,上面(?)处就可能不为null也不为正确值(尽管这个概率微乎其微),是一个中间值(不是完整的对象),这样就不能构造正确的单例。

    2022-10-26 23:35 回答
  • 第一个问题:
    volatile可以保证共享变量的"可见性",意思就是说当一个线程修改了变量,另外的线程能读到这个修改的值;
    实现是通过lock指令,lock指令回将处理器缓存写回到内存,当一个处理器缓存写回到内存会导致其他处理器的缓存失效,当其他处理器获取缓存数据发现缓存失效就会重新从内存中读取数据

    2022-10-26 23:35 回答
  • 1、volatile保证了uniqueInstance的修改对各个线程的可见性。
    2、这是个static方法synchronized(this)肯定是不行的,因为没有this。再说synchronized(uniqueInstance)synchronized是针对对象而言的,对象都是堆里的对象,但是初始化状态下uniqueInstancenull,只是栈里的一个标识,在堆里没有。我试了一下synchronized(null)会报空指针异常。

    2022-10-26 23:35 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有