Java 在获取对象变量的锁时重新分配对象变量
以下代码有意义吗: 线程A:Java 在获取对象变量的锁时重新分配对象变量,java,multithreading,synchronized,Java,Multithreading,Synchronized,以下代码有意义吗: 线程A: synchronized(mObj) { return mObj.x; } 线程B: synchronized(mObj) { mObj = new Object(); } 特别是,是否保证两个同步的部分始终是互斥的?此处未正确实现“无同步” 每个对象在执行时都有一个锁,并激活锁并在完成后释放锁,然后下一个线程将激活等待该锁的线程 mObj = new Object(); 重新分配新对象将在这方面产生冲突 假设一个场景——第一个线程T1通过获取
synchronized(mObj) {
return mObj.x;
}
线程B:
synchronized(mObj) {
mObj = new Object();
}
特别是,是否保证两个同步的部分始终是互斥的?此处未正确实现“无同步” 每个对象在执行时都有一个锁,并激活锁并在完成后释放锁,然后下一个线程将激活等待该锁的线程
mObj = new Object();
重新分配新对象将在这方面产生冲突
假设一个场景——第一个线程T1通过获取锁来执行同步部分,而线程t2正在等待获取线程T1获取的锁。现在,线程T1用新的对象重新分配mObj
对象,并通过释放对象(旧对象)锁离开同步部分,线程t2现在能够激活锁并进入同步块
此时,如果线程T3尝试执行同步化的块,“线程T3是否能够获取锁?”。答案是肯定的synchronized(mObj)
nowmObj
reference正在引用一个新对象,并且没有人获得锁,因此T3可以这样做。所以这是一种矛盾的情况。锁不在变量上,只在对象上
下面是一个计划,它表明这不是“线程安全的”,因为生成的计划没有保证
mObj = X
synchronized(mObj) // B1 -> mObj evaluates to X
mObj = Y // B2
DoSomeWork() // B3
synchronized(mObj) // A1 -> mObj MAY evaluate to either X or Y
// because the evaluation of the variable is NOT
// within scope of the synchronization. If it
// evaluates to Y then it is NOT synchronized on X.
return mObj.x // A2 -> May or may not be mutually exclusive wrt B3
// (That is, neither case is "guaranteed".)
我在“Thread B”同步上下文的末尾添加了一个“DoSomeWork”来绘制我的参数,但我认为相同的逻辑/参数-它的“可能是X或Y”-可以在没有这样的逻辑/参数的情况下应用,因此认为这两个同步块不能保证相互排斥。回答您的问题“是否保证两个同步部分始终相互排斥”
是的,这将是相互排斥的,但不是人们想要的方式
场景1:假设Thread1获得了监视器对象并首先进入同步块,那么Thread2显然会等待,重新分配mObj不会有任何效果。快乐场景:)
场景2:线程2获得监视器锁并首先进入同步块,线程1正在等待mObj。现在,当您将mObj重新分配给新对象mObj1时,它将更改监视器对象,这将导致线程1永远等待监视器锁,因为当线程2从同步块中出来时,它将释放锁对于监视对象mObj1而不是mObj,这就是为什么我说,它仍然是互斥的,但不是人们想要的方式:)
场景3:如果您正在使用等待通知解决方案,然后执行相同的操作,那么这将是灾难性的,并导致您出现IllegalMonitorState异常,原因与您在重新分配obj时尝试在没有锁定/同步块的某个监视器上等待或通知的原因相同。锁定不在变量上,只有对象。用作锁的变量应声明为final
,以避免此类错误。您的场景并不是真的有问题。问题在于,如果第一个线程获取锁,进入同步部分,重新分配变量,然后另一个线程能够进入同步部分,即使第一个线程打开e还没有离开它,因为线程现在在两个不同的对象上同步。嗯,不完全是我认为有点复杂的场景。呵呵,你的问题陈述很简短或令人印象深刻。在你介绍最后一段之前,我发表了我的评论。不过,你不需要3个线程来说明问题。