我到底需要同步什么,对象或对象内部的数据



假设我有一个类[X](及其对象[xObject]),其中有两个整数[a]和[B]。我有两个线程,一个修改[A],另一个修改[B]。现在,由于两个线程都更改了[xObject]的值,我应该同步访问[xObject]还是只同步[A]和[B],因为它们(实际上)有不同的内存位置。这个FALL在哪里结束,比如我应该同时访问数组中的两个不同位置,还是在arrayList中?

如果有两个独立的int属性,则根本不需要同步:同步的唯一原因是在涉及多个内存位置时确保一致性。对于独立的位置,volatile足以确保更改的跨线程可见性。

例如,如果int属性不是独立的,则需要进行同步。假设一个属性表示当前值,另一个表示最大值。设置大于最大值的当前值会引发异常;将最大值设置为大于当前值将当前值更改为新的最大

public class Test {
    int current = 10;
    int max = 100;
    public synchronized int getMax() { return max; }
    public synchronized int getCurrent() { return max; }
    public synchronized void setCurrent(int c) {
        if (c > max) throw new IllegalStateException();
        current = c;
    }
    public synchronized void setMax(int m) {
        max = m;
        if (current > m) current = m;
    }
}

数组和集合的决策更为复杂:如果您访问数组元素,但数组本身保持固定,并且数组元素是独立的,则可以跳过同步。但是,如果元素不是独立的,或者集合更复杂(例如数组列表或哈希表),则需要同步,因为集合操作可能会在结构上更改集合,从而破坏一致性。

不确定您对数组等的意思。但是,如果您更改两个不同的值,而不在另一个线程中读取它们,则不需要同步。

如果您在线程1中更改变量xObject.a的值,并在线程2或其他线程3中读取它,那么您可能会得到过时的读取,除非您在类X中生成一个易失性。

或者使用java.util.courrent包中的一个同步实用程序。可以四处搜索或在stackoverflow中搜索这样的例子。

如果您的类要在多线程环境中使用,我认为锁定使用getter或公共访问的任何可用数据是一个很好的做法。

这样你就不会强迫用户(使用你的类作为API的代码)知道或考虑特定的规则("如果你正在访问B,就不应该修改A")等。你可以直接使用可用的方法,而不必担心需要在哪个数据项上同步。此外,文档更少;)

这取决于客户端永远不应该看到的中间状态。

例如,如果对象不允许A和B的任何组合,那么您应该通过两种访问进行同步:

class Person {
  private final Object _lock = new Object(); // for synchronization
  private int _age;
  private boolean _married;
  public void setAge(int age) {
    if (age <= 0) throw new IllegalArgumentException();
    synchronized(_lock) {
        // age < 18 implies !married
        _age = age;
        if (age < 18) married = false;
    }
  }
}

即使A和B彼此独立,你也可能想这样做:

class ComplexNumber {
  private final Object _lockRe = new Object();
  private final Object _lockIm = new Object();
  private int _re, _im;
  ...
  public void setValue(int re, int im) {
    synchronized(_lockRe) { _re = re; }
    synchronized(_lockIm) { _im = im; }
  }
}

如果你做

ComplexNumber c = new ComplexNumber(0, 0);
c.setValue(1, 2);

那么线程可能会看到(1,0),但它从未设置过:这可能是可以接受的,也可能不是,这取决于您的应用程序。

相关内容

  • 没有找到相关文章

最新更新