div*_*ivz 81 java multithreading synchronized
每次在非最终类字段上同步时都会显示警告.这是代码:
public class X
{
private Object o;
public void setO(Object o)
{
this.o = o;
}
public void x()
{
synchronized (o) // synchronization on a non-final field
{
}
}
}
Run Code Online (Sandbox Code Playgroud)
所以我用以下方式改变了编码
public class X
{
private final Object o;
public X()
{
o = new Object();
}
public void x()
{
synchronized (o)
{
}
}
}
Run Code Online (Sandbox Code Playgroud)
我不确定上面的代码是在非final类字段上同步的正确方法.如何同步非最终字段?
aio*_*obe 117
首先,我鼓励您真正努力在更高级别的抽象上处理并发问题,即使用java.util.concurrent中的类来解决它,例如ExecutorServices,Callables,Futures等.
话虽如此,在非最终字段本身同步是没有错的.您只需要记住,如果对象引用发生更改,则可以并行运行相同的代码段.即,如果一个线程在同步块中运行代码并且有人调用setO(...),则另一个线程可以同时在同一个实例上运行相同的同步块.
同步您需要独占访问的对象(或者更好的是,"保护"它的对象).
Jon*_*eet 43
这真的不是一个好主意 - 因为您的同步块不再以一致的方式真正同步.
假设同步块旨在确保一次只有一个线程访问某些共享数据,请考虑:
你为什么要这样呢?也许有一些非常特殊的情况,这是有道理的......但是在我满意之前你必须向我提供一个特定的用例(以及减轻我上面给出的那种情况的方法).它.
Mar*_*cus 12
我同意John的评论之一:在访问非final变量时必须始终使用最终锁定虚拟对象,以防止变量引用更改时出现不一致.所以在任何情况下,作为第一个经验法则:
规则#1:如果某个字段是非最终字段,请始终使用(私有)最终锁定虚拟字符.
原因#1:您持有锁并自行更改变量的引用.在同步锁外等待的另一个线程将能够进入受保护的块.
原因#2:您持有锁,另一个线程更改变量的引用.结果是一样的:另一个线程可以进入受保护的块.
但是当使用最终的锁定虚拟时,还有另一个问题:您可能会得到错误的数据,因为在调用synchronize(object)时,非最终对象只会与RAM同步.所以,作为第二个经验法则:
规则#2:当锁定非最终对象时,您始终需要同时执行这两项操作:为了RAM同步,使用最终锁定虚拟对象和非最终对象的锁定.(唯一的替代方法是将对象的所有字段声明为volatile!)
这些锁也称为"嵌套锁".请注意,您必须始终以相同的顺序调用它们,否则您将获得死锁:
public class X {
private final LOCK;
private Object o;
public void setO(Object o){
this.o = o;
}
public void x() {
synchronized (LOCK) {
synchronized(o){
//do something with o...
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,我将两个锁直接写在同一行上,因为它们总是在一起.像这样,你甚至可以做10个嵌套锁:
synchronized (LOCK1) {
synchronized (LOCK2) {
synchronized (LOCK3) {
synchronized (LOCK4) {
//entering the locked space
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,如果您只是synchronized (LOCK3)通过其他线程获取内部锁,则此代码不会中断.但如果你调用另一个类似这样的线程,它会破坏:
synchronized (LOCK4) {
synchronized (LOCK1) { //dead lock!
synchronized (LOCK3) {
synchronized (LOCK2) {
//will never enter here...
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
处理非最终字段时,只有一种解决方法可以解决此类嵌套锁:
规则#2 - 备选:将对象的所有字段声明为volatile.(我不会在这里讨论这样做的缺点,例如,即使对于读取,也要防止在x级缓存中存储任何内容.)
所以aioobe是非常正确的:只需使用java.util.concurrent.或者开始了解有关同步的所有内容,并使用嵌套锁自行完成.;)
有关非最终字段上的同步中断的更多详细信息,请查看我的测试用例:https://stackoverflow.com/a/21460055/2012947
有关RAM和缓存需要同步的更多详细信息,请访问:https://stackoverflow.com/a/21409975/2012947
| 归档时间: |
|
| 查看次数: |
51256 次 |
| 最近记录: |