如何单独同步数据成员



我一直在网上搜索这篇文章,但找不到任何接近这篇文章的文章,对此我感到非常惊讶。也许智慧隐藏在我尚未发现的某个地方。

假设我有一个类,它有10个不同类型的成员(为了简单起见,假设它们混合了int和Strings),并且每个成员都有自己的访问器方法。现在,我想使这个类线程安全。但是,其中一些数据成员并不一定相互作用。例如,下面的类Person具有agename以及其他属性。

public class Person {
private volatile int age;
private String name;
private volatile long blabla;
// ... and so on
public synchronized int getAge() {
return age;
}
public synchronized void setAge(int age) {
this.age = age;
}
// .. and so on for each data member
}

一个线程可能只需要读/写age,而其他线程只需要修改name。显然,将synchronized添加到每个访问器方法是个坏主意,因为它会锁定对象的整个实例。调用getAge()的线程必须等待另一个调用getName()的线程,即使agename是两个独立的字段。

因此,一个显而易见的解决方案是为每个字段创建一个锁(或者将volatile添加到基元类型中)。然而,这似乎有些过头了。如果我有10个数据成员,我是否也需要10个锁?我想知道是否有另一种方法可以在不过度锁定的情况下实现这一点。

如果您关心同步基元类型,这是AtomicInteger等的一个极好的用例。它们非常快,可以确保线程安全。更多信息:

http://docs.oracle.com/javase/tutorial/essential/concurrency/atomicvars.html

首先,如果您谈论的是基元(或像String这样的不可变对象),那么您只需要标记每个字段volatile。如果您所做的只是获取和设置字段值,则不需要锁定。

然而,如果你的get/set方法执行多个操作,并且需要synchronized块,那么对我来说,每个字段有一个synchronized块似乎是过早的优化。我认为在像Person这样的小对象上使用synchronized方法是实现这一点的一种非常合适的方式。除非你有真正的原因(即探查器输出),否则我不会试图让它变得更复杂当然在任何情况下,每个字段的锁定都是过分的。

如果这种方法需要很长时间,就会有所不同。那么您就不想锁定整个对象并阻止其他访问者了。那么现在是拥有多个锁的好时机——每个锁用于单独的计算。但是,如果您的对象确实只是试图保护get/set,那么synchronized方法就可以了。

其他评论:

  • 如果您只需要volatile字段,则不需要任何synchronized
  • 如果您有synchronized方法,那么您不需要将字段设为volatile
  • 如果没有写入name字段,则该字段可能应标记为final

最新更新