为什么内在锁对象不需要特殊处理(static、final、volatile)?
Why intrinsic lock object do not require special treatment (static, final, 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++;
}
}
}
有很多问题在争论 volatile 与同步块
- volatile fields and synchronized blocks,
- difference between volatile and synchronized in java
- when to use volatile vs synchronization in multithreading in java,
- do you ever use the volatile keyword in java
和不可变对象
- what are immutable objects,
- immutability and synchronization in java
- immutable objects java concurreny) 在多线程中。
附带说明一下,我理解声明对象 final 与不可变性之间的细微差别 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对象作为锁。
既然多线程访问的对象需要像上面那样使用某种机制来保证原子访问,为什么内在锁对象不需要特殊处理呢?
这些锁不需要特殊处理,因为 MsLunch
对象本身需要先发布才能被任何其他线程看到。
public class MyMain {
public static void main(String... args) {
MsLunch lunch = new MsLunch();
// ...
这是线程安全的,因为局部变量 ("lunch
") 对多个线程不可见。
下面的 class 使本地引用对系统中的所有线程可见。当发生这种情况时,我们需要使用 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;
//...
}
}
In this oracle example of intrinsic locks and many more, the monitor object is never declared as volatile, final or nor it has any distinction from any other regular object.
事实并非如此。见下文。
Since for an object which is accessed by multiple threads you need to use some mechanism as above to ensure atomic access, why is that for intrinsic lock object there is no need for any special treatment?
确实有特殊待遇。它是同步的。
它可能应该是最终的。但是 final 并不是什么特别的东西——它只在一种特殊情况下需要(将函数内部声明的变量引用到匿名 class 中)。任何其他情况下的 final 只是提醒程序员不要覆盖变量 - 您可以删除程序中所有其他使用 final 一词的地方,它会完美地工作。你是对的,程序员可以分配给它然后导致问题。但如果他不这样做,就没有问题。因此,在创建程序时继续使用 final,但程序编译不需要它。
至于静态 - 取决于用例。您要监控 class 的所有实例还是独立监控每个实例?在第一种情况下,您使用 static,而在第二种情况下您不使用。
不需要 Volatile,因为该对象实际上并未被多个线程更改。它正在同步。这是完全不同的,并且是 Java 语言中比 volatile 更老的部分。没有必要将变量设为 volatile,因为您不会更改它,并且用于监视对象的内部数据结构已经知道它们需要线程安全(并且比 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++; } } }
有很多问题在争论 volatile 与同步块
- volatile fields and synchronized blocks,
- difference between volatile and synchronized in java
- when to use volatile vs synchronization in multithreading in java,
- do you ever use the volatile keyword in java
和不可变对象
- what are immutable objects,
- immutability and synchronization in java
- immutable objects java concurreny) 在多线程中。
附带说明一下,我理解声明对象 final 与不可变性之间的细微差别 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对象作为锁。
既然多线程访问的对象需要像上面那样使用某种机制来保证原子访问,为什么内在锁对象不需要特殊处理呢?
这些锁不需要特殊处理,因为 MsLunch
对象本身需要先发布才能被任何其他线程看到。
public class MyMain {
public static void main(String... args) {
MsLunch lunch = new MsLunch();
// ...
这是线程安全的,因为局部变量 ("lunch
") 对多个线程不可见。
下面的 class 使本地引用对系统中的所有线程可见。当发生这种情况时,我们需要使用 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;
//...
}
}
In this oracle example of intrinsic locks and many more, the monitor object is never declared as volatile, final or nor it has any distinction from any other regular object.
事实并非如此。见下文。
Since for an object which is accessed by multiple threads you need to use some mechanism as above to ensure atomic access, why is that for intrinsic lock object there is no need for any special treatment?
确实有特殊待遇。它是同步的。
它可能应该是最终的。但是 final 并不是什么特别的东西——它只在一种特殊情况下需要(将函数内部声明的变量引用到匿名 class 中)。任何其他情况下的 final 只是提醒程序员不要覆盖变量 - 您可以删除程序中所有其他使用 final 一词的地方,它会完美地工作。你是对的,程序员可以分配给它然后导致问题。但如果他不这样做,就没有问题。因此,在创建程序时继续使用 final,但程序编译不需要它。
至于静态 - 取决于用例。您要监控 class 的所有实例还是独立监控每个实例?在第一种情况下,您使用 static,而在第二种情况下您不使用。
不需要 Volatile,因为该对象实际上并未被多个线程更改。它正在同步。这是完全不同的,并且是 Java 语言中比 volatile 更老的部分。没有必要将变量设为 volatile,因为您不会更改它,并且用于监视对象的内部数据结构已经知道它们需要线程安全(并且比 volatile 承诺更强大)。