为什么内部锁定对象不需要特殊处理(静态,最终,易失性)?

时间:2016-02-28 18:49:55

标签: java multithreading synchronization immutability volatile

在这个oracle example内在锁等等中,监视器对象永远不会被声明为volatile,final或者它与任何其他常规对象没有任何区别

public class MsLunch {
    private long c1 = 0;
    private long c2 = 0;
    private Object lock1 = new Object();
    private Object lock2 = new Object();

    public void inc1() {
        synchronized(lock1) {
            c1++;
        }
    }

    public void inc2() {
        synchronized(lock2) {
            c2++;
        }
    }
}

有很多问题讨论易失性和同步块

和不可变对象

作为旁注,我理解声明对象最终与不变性why-can-final-object-be-modified之间的细微差别以及为什么将锁定对象声明为final将不会使其成为不可变的。

但是,我们有着名的singleton class延迟初始化模式,其中使用volatile变量是必不可少的。

public class SingletonDemo {
    private static volatile SingletonDemo instance;
    private SingletonDemo() { }

    public static SingletonDemo getInstance() {
        if (instance == null ) {
            synchronized (SingletonDemo.class) {
                if (instance == null) {
                    instance = new SingletonDemo();
                }
            }
        }

        return instance;
    }
}

在上面的code example中使用Class对象作为锁。

由于对于多个线程访问的对象,您需要使用上述某种机制来确保原子访问,为什么内部锁定对象不需要任何特殊处理? < / p>

3 个答案:

答案 0 :(得分:1)

这些锁不需要特殊处理,因为MsLunch对象本身需要在任何其他线程可以看到之前发布。

public class MyMain {
  public static void main(String... args) {
    MsLunch lunch = new MsLunch();
    // ...

这是线程安全的,因为局部变量(&#34; lunch&#34;)对多个线程不可见。

接下来,下面的类使本地引用对系统中的所有线程可见。当发生这种情况时,我们需要使用volatilevolatile关键字有效地创建了一个安全地发布对象的内存屏障。这包括在分配之前进行的所有写入,包括在构造对象时在内部进行的写入。

C.f。 Safe Publication

public class MyMain {

  public static volatile MsLunch publicLunch;

  public static void main(String... args) {
    MsLunch lunch = new MsLunch();
    publicLunch = lunch;
    //...
  }
}

答案 1 :(得分:0)

它可能应该是最终的。但是final并不是什么特别的东西 - 它只在一个特殊情况下需要(将函数内部声明的变量引用到匿名类中)。任何其他案例最终只是提醒程序员不要覆盖变量 - 你可以删除程序中单词final的所有其他用法,它将完美地工作。你是对的,程序员可以分配它然后引起问题。但如果他没有,那就没有问题。所以在创建一个时继续使用final,但编译程序不是必需的。

至于静态 - 取决于用例。是否要独立监视类的所有实例或每个实例?在第一种情况下,您在第二种情况下使用静态,而不是

不需要易失性,因为多个线程实际上没有改变对象。它正在同步。这是完全不同的,并且Java语言的旧部分比易失性。当你不想改变它时,不需要使变量变为volatile,并且用于监视对象的内部数据结构已经知道它们需要是线程安全的(并且比volatile更强大)许)。

答案 2 :(得分:-1)

  

在这个本机锁的oracle示例中,监视器对象永远不会被声明为volatile,final或者它与任何其他常规对象没有任何区别。

那不是真的。见下文。

  

由于对于多个线程访问的对象,您需要使用上述某种机制来确保原子访问,为什么内部锁定对象不需要任何特殊处理?

确实有特殊待遇。它是同步的。