我一直在阅读使用静态对象作为锁,最常见的例子是这样的:
public class MyClass1 {
private static final Object lock = new Object();
public MyClass1() {
//unsync
synchronized(lock) {
//sync
}
//unsync
}
}
我的问题是锁是否必须是最终的?我理解将它作为最终确定没有人会对价值感到困惑是好的,但它会在没有最终的情况下发挥作用吗?
当然,它会起作用 - 直到你重新分配它。如果lock
不是最终的,那么有人可以为它指定另一个值(lock = new Object()
)。这就像更换门上的锁:如果你还有旧钥匙,你将无法再使用锁。
制作lock
final会阻止这种情况发生,因此这样做总是一个好主意。
如果你没有制作变量final
,你可以在NullPointerException
的构造函数中得到一个MyClass1
,如果你在与加载MyClass1
的线程不同的线程中创建MyClass1
的实例。
final
修饰符保证lock
安全发布的方式没有final
没有。
此外,如果它不是final
,它可能会被更改,导致您锁定错误的对象实例。
您可以在第17章(“线程和锁定”)中找到有关final
修饰符在Java Language Specification Section 17.5 ("Final Field semantics")中安全发布方面提供的保证的更多信息。
基本上你必须确保一旦创建了锁定对象,没有人会以任何方式搞砸它。因此,你必须使用constant
制作static final
。 So, by creating a constant we are making sure that our lock object is created as soon as the class is loaded and never modify that in application lifetime.
奖金:
另一种方法是使用static initializer
。这非常适合您希望在多个语句中执行锁定对象分配的情况。下面的例子如下:
public class Test {
private static final Test lockObject;
static {
System.out.println("Hello");
lockObject = new Test();
}
public static void main(String[] args) {
synchronized (lockObject) {
//your code goes here
}
}
}
如果以不同的方式编写它可能更直观:它与此几乎相同
public class MyClass {
static Lock myLock = new ReentrantLock();
public MyClass1() {
//unsync
myLock.lock();
//sync
myLock.unlock();
//unsync
}
}
与myLock
最终与否的相同后果。
如果它不是final
并被重新分配,则锁定状态将无关紧要。
无论如何,我建议使用Lock
课程。