在java中同步一个对象,然后改变synchronized-on变量的值
我遇到这样的代码,
synchronized(obj) {
obj = new Object();
}
感觉有些不对劲,我无法解释,这段代码是否OK或者确实有问题,请指出。 谢谢
I came across a code like this
synchronized(obj) {
obj = new Object();
}
Something does not feel right about this , I am unable to explain, Is this piece of code OK or there is something really wrong in it, please point it out.
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这可能不是您想要做的。您正在同步一个不再持有引用的对象。考虑运行此方法的另一个线程:在对 obj 的引用更新为指向新对象后,它们可能会进入并尝试锁定锁。此时,它们正在与第一个线程不同的对象上进行同步。这可能不是您所期望的。
除非您有充分的理由不这样做,否则您可能希望在最终对象上进行同步(为了可见性)。在这种情况下,您可能希望使用单独的锁定变量。例如:
It's probably not what you want to do. You're synchronizing on an object that you're no longer holding a reference to. Consider another thread running this method: they may enter and try to hit the lock at the moment after the reference to
obj
has been updated to point to the new object. At that point, they're synchronizing on a different object than the first thread. This is probably not what you're expecting.Unless you have a good reason not to, you probably want to synchronize on a final Object (for visibility's sake.) In this case, you would probably want to use a separate lock variable. For example:
如果 obj 是一个局部变量,并且没有其他线程正在评估它以获取它的锁如此处所示,那么它不会没关系。否则,这会严重破坏,并且适用以下内容:(
发布此内容是因为其他答案措辞不够强烈——“可能”在这里不够充分——并且没有足够的细节。)
每次线程遇到同步块时,
在获取锁之前,它必须通过评估synchronized关键字后面的括号中的表达式来确定需要锁定哪个对象。
如果在线程计算该表达式之后引用被更新,则线程无法知道这一点。它将继续获取它之前识别为锁的旧对象上的锁。最终它进入旧对象上的同步块锁定,而另一个线程(在锁更改后尝试进入该块)现在将该锁评估为新对象,并进入持有新锁的同一对象的同一块,并且你们没有相互排斥。
JLS 中的相关部分是 14.19< /a>.执行同步语句的线程:
1) 计算表达式,然后
2) 获取表达式计算结果的锁,然后
3) 执行块。
它在成功获取锁时不会再次重新访问评估步骤。
这段代码已损坏。不要这样做。锁定那些不会改变的事情。
If obj is a local variable and no other thread is evaluating it in order to acquire a lock on it as shown here then it doesn't matter. Otherwise this is badly broken and the following applies:
(Posting this because the other answers are not strongly-worded enough --"probably" is not sufficient here -- and do not have enough detail.)
Every time a thread encounters a synchronized block,
before it can acquire the lock, it has to figure out what object it needs to lock on, by evaluating the expression in parens following the synchronized keyword.
If the reference is updated after the thread evaluates this expression, the thread has no way of knowing that. It will proceed to acquire the lock on the old object that it identified as the lock before. Eventually it enters the synchronized block locking on the old object, while another thread (that tries to enter the block after the lock changed) now evaluates the lock as being the new object and enters the same block of the same object holding the new lock, and you have no mutual exclusion.
The relevant section in the JLS is 14.19. The thread executing the synchronized statement:
1) evaluates the expression, then
2) acquires the lock on the value that the expression evaluates to, then
3) executes the block.
It doesn't revisit the evaluation step again at the time it successfully acquires the lock.
This code is broken. Don't do this. Lock on things that don't change.
在这种情况下,有人可能认为他们正在做的事情没问题,但这可能不是他们想要的。在本例中,您正在同步 obj 变量中的当前值。一旦创建了一个新实例并将其放入 obj 变量中,锁定条件就会发生变化。如果这就是该块中发生的所有事情,那么它可能会起作用 - 但如果它之后执行任何其他操作,则该对象将无法正确同步。
最好是安全并在包含对象上或完全在另一个互斥体上同步。
This is a case where someone might think what they are doing is OK, but it probably isn't what they intended. In this case, you are synchronizing on the current value in the obj variable. Once you create a new instance and place it in the obj variable, the lock conditions will change. If that is all that is occurring in this block, it will probably work - but if it is doing anything else afterwards, the object will not be properly synchronized.
Better to be safe and synchronize on the containing object, or on another mutex entirely.
这是一种不常见的用法,但在相同的场景中似乎是有效的。我在 JmDNS 的代码库中发现了一个:
它的作用是同步返回的列表,这样该列表就不会被其他人修改,然后复制该列表。在这种特殊情况下,仅原始对象需要锁。
It's a uncommon usage but seems to be of valid in same scenarios. One I found in the codebase of JmDNS:
What it does is to synchonize on the returned list so this list does not get modified by others and then makes a copy of this list. In this special situation the lock is only needed for the original object.