是的,可以。所有非最终变量/字段都可以随时更改其值/对对象的引用,无论对象是在受保护块内部还是外部。因此,您始终需要结合非最终字段使用第三方锁:
private static Object myTable;
private final static Object LOCK;
....
synchronized(LOCK){
//access myTable here...
}
只有将字段设置为 final 才能防止任何来自锁内部或外部的引用更改。可以说后者是一种错误的 Java 行为,并且应该通过调用 synchronized 来锁定引用。但这就是它需要的方式,否则代码将变得无法维护。
嗯,至少需要一些像private guardable Object o; 这样的新字段来达到这个目的。 ;)
编辑:
这是 Test 类中的一个测试用例(请注意,构造函数会加载非常不可预测的线程,因此 wait(1000)...但这只是一个测试,通常你根本不应该在构造函数中启动线程):
private volatile boolean first = true;
private TestObject testObject;
private Thread thread;
public Test(){
testObject = new TestObject();
thread = new Thread(this);
thread.start();
try {
synchronized(this){
wait(1000);
}
} catch (InterruptedException ex) {}
first = false;
thread = new Thread(this);
thread.start();
}
public void run() {
System.out.println("First: "+testObject.toString());
if(!first){
testObject = new TestObject();
}
synchronized(testObject){
System.out.println("Second: "+testObject.toString()+" locked!");
try {
synchronized(this){
System.out.println("Thread "+thread+" waiting!");
wait();
}
} catch (InterruptedException ex) {}
}
}
public static void main(String[] args) {
Test test = new Test();
}
结果是:
First: model.TestObject@12b6651
Second: model.TestObject@12b6651 locked!
Thread Thread[Thread-0,5,main] waiting!
First: model.TestObject@12b6651
Second: model.TestObject@4a5ab2 locked!
Thread Thread[Thread-1,5,main] waiting!
您可以在第 5 行看到 锁无法阻止引用更改。然后将测试用例改为:
private volatile boolean first = true;
private TestObject testObject;
private Thread thread;
private final Object LOCK = new Object();
...
public void run() {
System.out.println("First: "+testObject.toString());
if(!first){
testObject = new TestObject();
}
synchronized(LOCK){
...
产生这个结果:
First: model.TestObject@150bd4d
Second: model.TestObject@150bd4d locked!
Thread Thread[Thread-0,5,main] waiting!
First: model.TestObject@150bd4d
这里第二个线程等待获取LOCK,这正是我们想要的。