关于线程安全代码的问题

aks*_*hay 0 java synchronization thread-safety

我有一个课程如下

public MyClass{

Boolean flag = false;

    public Boolean getflag(){
       synchronized(flag){
          //BLOCK 1
          return flag;
       }
    }

    public Boolean setflag(){
       synchronized(flag){
           //BLOCK 2
           this.flag = flag;
       }
    }
}
Run Code Online (Sandbox Code Playgroud)

两种方法都在对象标志上同步.现在我怀疑是两个不同的线程可以同时执行同步块(1和2).可能出现以下情况吗?1)线程1是设置标志值,线程2是否同时获取其值?

Pét*_*rök 9

是的,它可以.请注意,您正在同步所设置的同一对象.因此,setter可以将对象引用更改为不同的东西,然后当setter仍在synchronized块内时,getter可以在新对象上进行同步.

但是,还有更多:flag(通常)一个以全系统的单身一个参考Boolean.TRUEBoolean.FALSE,因此它是(至少在理论上)可能锁定在这些类之外,即使没有提及你的类以任何方式.在这种情况下,你最终可能会陷入僵局,你可能很难搞清楚原因.

(另请注意,当前形式的代码是错误的,因为setter没有参数,因此this.flag = flag将引用分配给它自己 - 但是上面我假设你的意思是它表现得像普通的setter :)

修复是使用一个专用的private final锁定对象(如果你想绝对确保外面的任何人都可以在你的类中使用的同一个锁上同步 - 我想你的初衷是):

public MyClass{

    private final Object lock = new Object();
    private Boolean flag = false;

    public Boolean getflag(){
       synchronized(lock){
          //BLOCK 1
          return flag;
       }
    }

    public void setflag(Boolean flag){
       synchronized(lock){
           //BLOCK 2
           this.flag = flag;
       }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你不担心内部使用的同一个锁上的其他同步,你可以简单地制作你的方法synchronized(在这种情况下它们会锁定this).