在这个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>
答案 0 :(得分:1)
这些锁不需要特殊处理,因为MsLunch
对象本身需要在任何其他线程可以看到之前发布。
public class MyMain {
public static void main(String... args) {
MsLunch lunch = new MsLunch();
// ...
这是线程安全的,因为局部变量(&#34; lunch
&#34;)对多个线程不可见。
接下来,下面的类使本地引用对系统中的所有线程可见。当发生这种情况时,我们需要使用volatile
。 volatile
关键字有效地创建了一个安全地发布对象的内存屏障。这包括在分配之前进行的所有写入,包括在构造对象时在内部进行的写入。
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或者它与任何其他常规对象没有任何区别。
那不是真的。见下文。
由于对于多个线程访问的对象,您需要使用上述某种机制来确保原子访问,为什么内部锁定对象不需要任何特殊处理?
确实有特殊待遇。它是同步的。