当多个线程通过getter方法访问类字段时,如何保持线程安全? synchronized参数是否足够?

这是安全的吗?

public class SomeClass {
    private int val;

    public synchronized int getVal() {
        return val;
    }

    private void setVal(int val) {
        this.val = val;
    }
}

或者是否会引入进一步的并发症?

有帮助吗?

解决方案

如果您也在此处使用setter上的'synchronized',则此代码是线程安全的。但是它可能不够细小;如果你有20个getter和setter并且它们都是同步的,你可能会创建一个同步瓶颈。

在这个特定的实例中,使用单个int变量,然后消除'synchronized'并将int字段标记为'volatile'也将确保可见性(每个线程在调用getter时将看到'val'的最新值)但是它可能无法满足您的需求。例如,期待

 int old = someThing.getVal();
 if (old == 1) {
    someThing.setVal(2);
 }

将val设置为2当且仅当它已经为1时才是错误的。为此,您需要一个外部锁或一些原子比较和设置方法。

我强烈建议您阅读Brian Goetz 中的 Java Concurrency In Practice ,它具有Java并发构造的最佳覆盖范围。

其他提示

除了 Cowan的评论,您可以进行以下比较和存储:

synchronized(someThing) {
    int old = someThing.getVal();
    if (old == 1) {
        someThing.setVal(2);
    }
}

这是有效的,因为通过synchronized方法定义的锁与对象的锁隐式相同(参见java语言规范)。

根据我的理解,你应该在getter和setter方法上使用synchronized,这就足够了。

编辑:这是链接关于同步的更多信息以及不同步的信息。

如果您的类只包含一个变量,那么实现线程安全的另一种方法是使用现有的AtomicInteger对象。

public class ThreadSafeSomeClass {

    private final AtomicInteger value = new AtomicInteger(0);

    public void setValue(int x){
         value.set(x);
    }

    public int getValue(){
         return value.get();
    }

}

但是,如果添加其他变量以使它们相关(一个变量的状态取决于另一个变量的状态),则AtomicInteger将不起作用。

回应建议,阅读“Java Concurrency in Practice”。

对于简单的物体,这可能就足够了。在大多数情况下,您应该避免使用synchronized关键字,因为您可能会遇到同步死锁。

示例:

public class SomeClass {

  private Object mutex = new Object();
  private int    val   = -1; // TODO: Adjust initialization to a reasonable start
                             //       value
  public int getVal() {
    synchronized ( mutex ) {
      return val;
    }
  }

  private void setVal( int val ) {
    synchronized ( mutex ) {
      this.val = val;
    }
  }
}

确保只有一个线程读取或写入本地实例成员。

阅读“Java中的并发编程(tm):设计原则和模式(Java(Addison-Wesley))”一书,可能 http://java.sun.com/docs/books/tutorial/essential/concurrency/index.html 也很有用..

存在同步以防止线程干扰和内存一致性错误。通过在getVal()上进行同步,代码可以保证SomeClass上的其他同步方法也不会同时执行。由于没有其他同步方法,因此没有提供太多价值。另请注意,对基元的读取和写入具有原子访问权限。这意味着通过仔细编程,不需要同步对字段的访问。

阅读 Sychronization

不确定为什么会降到-3。我只是总结一下Sun的同步教程(以及我自己的经验)。

  

使用简单的原子变量访问是   比访问这些更有效   变量通过同步代码,   但需要更多的照顾   程序员避免内存一致性   错误。是否额外的努力   值得取决于大小和   应用程序的复杂性。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top