Java 当锁持有非最终对象时,对象';s的引用仍将由另一个线程更改?
当需要同步对象时,如果未将其设置为非最终对象(因为其引用不是持久的),IDE会发出抱怨: 我们都知道,如果持有锁的线程更改了非最终对象的引用,IDE会抱怨阻止另一个线程进入保护块 但是,当线程a持有同一对象的锁时,另一个线程B是否也可以更改同步对象的引用 但是,当线程a持有同一对象的锁时,另一个线程B是否也可以更改同步对象的引用 如果您的意思是“另一个线程是否可以更改Java 当锁持有非最终对象时,对象';s的引用仍将由另一个线程更改?,java,multithreading,locking,synchronized,final,Java,Multithreading,Locking,Synchronized,Final,当需要同步对象时,如果未将其设置为非最终对象(因为其引用不是持久的),IDE会发出抱怨: 我们都知道,如果持有锁的线程更改了非最终对象的引用,IDE会抱怨阻止另一个线程进入保护块 但是,当线程a持有同一对象的锁时,另一个线程B是否也可以更改同步对象的引用 但是,当线程a持有同一对象的锁时,另一个线程B是否也可以更改同步对象的引用 如果您的意思是“另一个线程是否可以更改myTable变量的值,那么答案是“绝对”…假设有一个允许这样做的代码路径。它是一个私有变量,因此您应该能够找到所有可以更改该值的
myTable
变量的值,那么答案是“绝对”…假设有一个允许这样做的代码路径。它是一个私有变量,因此您应该能够找到所有可以更改该值的代码
持有一个锁只会阻止另一个线程获取同一个锁,它本身对什么代码可以访问哪些变量没有任何影响
作为旁注,区分对象、变量和变量的值(这是引用,而不是对象)很重要。因此,没有“最终对象”这样的东西——只有变量(以及类和方法)可以是最终对象。同样,也没有“同步对象”这样的东西,您不能更改对象的引用“-您可以更改变量的值,使其成为对不同对象的引用。把这些区别清楚地记在脑子里可能有助于你思考这里发生的事情。是的,它可以。所有非最终变量/字段都可以随时更改其对对象的值/引用,无论对象位于受保护块的内部还是外部。因此,您始终需要将第三方锁与非最终字段结合使用:
private static Object myTable;
private final static Object LOCK;
....
synchronized(LOCK){
//access myTable here...
}
仅将字段设置为final将防止从锁内部或外部进行任何引用更改。可以说后者是一种错误的Java行为,也应该通过调用synchronized来锁定引用。但这是它需要的方式,否则代码将变得无法维护
嗯,至少有一些新的字段,比如私有可保护对象o代码>将为此目的而需要。;)
编辑:
下面是类测试中的一个测试用例(请注意,构造函数加载的线程非常不可预测,因此等待(1000)…但这只是一个测试,通常您根本不应该在构造函数中启动线程):
结果是:
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
这里,第二个线程等待获取锁,这正是我们想要的。是的,这就是我的意思,可能标题应该是:“当一个锁持有非最终变量的对象时,该变量的值还能被另一个线程更改吗?”这都是为了找到正确的单词,对吗?;)@马卡斯:嗯,我还是不这么说。您用来获取锁的引用碰巧来自一个变量,但这只是因为它是当时变量的值。可能还有其他变量具有相同的引用。因此,再尝试一次:“当一个锁持有从非最终变量获取的对象时,该变量的值还能被另一个线程更改吗?”@Marcus:这至少更好,但锁不持有对象-它是与对象关联的锁(或监视器),它是一根固定锁的线。更重要的是,“当一个线程持有一个对象的锁,而该对象的引用是通过非最终变量获得的,那么该变量的值还能被另一个线程更改吗?”但我可能不会用它作为标题:)
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