同步非最终字段

2022-08-31 10:00:27

每次我在非最终类字段上进行同步时都会显示一条警告。代码如下:

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  
     {  
     }  
   }  
 } 

所以我按以下方式更改了编码:

 public class X  
 {  

   private final Object o;       
   public X()
   {  
     o = new Object();  
   }  

   public void x()  
   {  
     synchronized (o)
     {  
     }  
   }  
 }  

我不确定上面的代码是在非最终类字段上进行同步的正确方法。如何同步非最终字段?


答案 1

首先,我鼓励你真正努力地在更高层次的抽象上处理并发问题,即使用java.util.concurrent中的类(如ExecutorServices,Callables,Futures等)来解决它。

话虽如此,在非最终字段本身上进行同步并没有。您只需要记住,如果对象引用发生更改,则可以并行运行同一段代码。也就是说,如果一个线程在同步块中运行代码并且有人调用,另一个线程可以同时在同一实例上运行相同的同步块setO(...)

在需要独占访问权限的对象(或者更好的是,专用于保护它的对象)上进行同步。


答案 2

这真的不是一个好主意 - 因为你的同步块不再以一致的方式真正同步。

假设同步块旨在确保一次只有一个线程访问某些共享数据,请考虑:

  • 线程 1 进入同步块。耶 - 它具有对共享数据的独家访问权限...
  • 线程 2 调用 setO()
  • 线程 3(或静止的 2...)进入同步的块。哎呀!它认为它对共享数据具有独占访问权限,但线程1仍然在使用它......

你为什么希望这种情况发生?也许有一些非常特殊的情况是有意义的......但是你必须向我展示一个特定的用例(以及减轻我上面给出的那种场景的方法),然后我才会满意。