java同步关键字需要在原始 getter / setter 方法上?

2022-09-04 07:02:50

我阅读了一些java代码,并找到了这些函数:

synchronized void setConnected(boolean connected){
   this.connected = connected;
}

synchronized boolean isConnected(){
   return connected;
}

我想知道同步在这里是否有任何意义,或者只是作者不理解同步关键字的必要性?

我认为同步在这里是无用的。还是我错了?


答案 1

关键字是确保线程安全的一种方法。请注意:线程安全比死锁更多,或者由于两个线程在没有同步的情况下递增一个int而缺少更新。synchronized

请考虑以下类:

class Connection {
  private boolean connected; 
  synchronized void setConnected(boolean connected){
    this.connected = connected;
  }
  synchronized boolean isConnected(){
    return connected;
  }
}

如果多个线程共享 一个实例和一个线程调用 ,则其他线程可能会继续看到 。关键字保证所有线程都能看到字段的当前值。ConnectionsetConnected(true)synchronizedisConnected() == falsesynchronized

在更技术的术语中,关键字确保了内存障碍(提示:谷歌)。synchronized

更详细地说:在释放监视器之前(即,在离开块之前)所做的每一次写入都保证在获取相同的监视器(即,在同一对象上进入同步块之后)进行的每一次读取都可以看到。在Java中,有一种叫做“发生在之前”(hint:google that)的东西,它不像“我按这个顺序编写代码,所以事情按照这个顺序执行”那么微不足道。使用是一种建立先发生关系并保证线程看到内存的方法,就像你期望它们看到的那样。synchronizedsynchronized

在这种情况下,实现相同保证的另一种方法是消除关键字并标记字段 。提供的保证如下:线程在易失性写入之前进行的所有写入都保证在对同一字段进行后续易失性读取后对线程可见。synchronizedvolatilevolatile

最后要注意的是,在这种特殊情况下,最好使用字段而不是访问器,因为这两种方法提供了相同的保证,而 -field 方法允许从不同的线程同时访问字段(如果版本有太多的争用,这可能会提高性能)。volatilesynchronizedvolatilesynchronized


答案 2

此处需要同步以防止内存一致性错误,请参阅 http://docs.oracle.com/javase/tutorial/essential/concurrency/memconsist.html。虽然在这个具体的情况下将是更有效的解决方案volatile

private volatile boolean connected;

void setConnected(boolean connected){
   this.connected = connected;
}

boolean isConnected(){
   return connected;
}

推荐