Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 当锁持有非最终对象时,对象';s的引用仍将由另一个线程更改?_Java_Multithreading_Locking_Synchronized_Final - Fatal编程技术网

Java 当锁持有非最终对象时,对象';s的引用仍将由另一个线程更改?

Java 当锁持有非最终对象时,对象';s的引用仍将由另一个线程更改?,java,multithreading,locking,synchronized,final,Java,Multithreading,Locking,Synchronized,Final,当需要同步对象时,如果未将其设置为非最终对象(因为其引用不是持久的),IDE会发出抱怨: 我们都知道,如果持有锁的线程更改了非最终对象的引用,IDE会抱怨阻止另一个线程进入保护块 但是,当线程a持有同一对象的锁时,另一个线程B是否也可以更改同步对象的引用 但是,当线程a持有同一对象的锁时,另一个线程B是否也可以更改同步对象的引用 如果您的意思是“另一个线程是否可以更改myTable变量的值,那么答案是“绝对”…假设有一个允许这样做的代码路径。它是一个私有变量,因此您应该能够找到所有可以更改该值的

当需要同步对象时,如果未将其设置为非最终对象(因为其引用不是持久的),IDE会发出抱怨:

我们都知道,如果持有锁的线程更改了非最终对象的引用,IDE会抱怨阻止另一个线程进入保护块

但是,当线程a持有同一对象的锁时,另一个线程B是否也可以更改同步对象的引用

但是,当线程a持有同一对象的锁时,另一个线程B是否也可以更改同步对象的引用

如果您的意思是“另一个线程是否可以更改
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