简体   繁体   English

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

[英]What Do I exactly need to Synchronize, Object or Data inside object

Suppose I have a class [X] (and its object [xObject]) and within it two Integers [A] and [B]. 假设我有一个类[X](及其对象[xObject]),并且其中有两个整数[A]和[B]。 I have two threads One modifies [A] and other modifies [B]. 我有两个线程:一个修改[A],另一个修改[B]。 Now, since both threads change the value of [xObject], should I be synchronizing access to [xObject] or just [A] and [B] because they have different memory location(actually). 现在,由于两个线程都更改了[xObject]的值,因此我应该同步访问[xObject]还是仅同步[A]和[B],因为它们(实际上)具有不同的内存位置。 And where this FALL ends,, like should I access two different locations in an array simultaneously, or inside an arrayList? 在这个FALL结束的地方,就像我应该同时访问数组中的两个不同位置还是在arrayList中?

not sure what you mean about arrays etc. But if your changing two different values and not reading them in the other thread you do not need to synchronize. 不确定您对数组等的含义。但是,如果更改两个不同的值而不在另一个线程中读取它们,则不需要同步。

If you are changing value of variable xObject.a in thread 1 and reading it in thread 2 or some other thread 3 then you might get stale reads unless you make a as volatile in class X. 如果要在线程1中更改变量xObject.a的值并在线程2或其他一些线程3中读取它,那么除非在类X中将a设为volatile,否则您可能会获得过时的读取。

Or use one of the synching utilities in java.util.concurrent package. 或使用java.util.concurrent包中的同步实用程序之一。 Can google around or search in stackoverflow for examples of that. 可以在周围搜索或在stackoverflow中搜索示例。

If you have two independent int properties, you don't need to synchronize at all: the only reason to synchronize is to ensure consistency when more than one memory location is involved. 如果您有两个独立的int属性,则根本不需要同步:进行同步的唯一原因是在涉及多个内存位置时确保一致性。 With independent locations volatile is sufficient to ensure cross-thread visibility of your changes. 在独立的位置上, volatile足以确保更改的跨线程可见性。

For example, if your int properties are not independent, you need to synchronize. 例如,如果您的int属性不是独立的,则需要进行同步。 Let's say one property represents the current value, and the other represents the max value. 假设一个属性代表当前值,另一个属性代表最大值。 Setting the current value that's greater than the max throws an exception; 设置大于最大值的当前值会引发异常; setting the max value greater than the current value changes the current value to the new max. 将最大值设置为大于当前值会将当前值更改为新的最大值。

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;
    }
}

The decision for arrays and collections is more complex: if you access array elements, but the array itself stays fixed, and array elements are independent, you can skip synchronization. 数组和集合的决定更加复杂:如果访问数组元素,但是数组本身保持固定,并且数组元素是独立的,则可以跳过同步。 However, if elements are not independent, or if the collection is more complex (say, an array list or a hash table) then you need to synchronize, because collection operations may change the collection structurally, breaking consistency. 但是,如果元素不是独立的,或者集合更复杂(例如,数组列表或哈希表),则需要进行同步,因为集合操作可能会在结构上改变集合,从而破坏一致性。

If your class is going to be used in a multi-threaded environment, I think its a good practice to lock any data that is made available using getters or public access. 如果您的类将在多线程环境中使用,我认为锁定使用getter或public访问提供的任何数据是一种很好的做法。

That way you are not forcing the users(code that uses your class as API) to know or consider specific rules("should not modify A if you are accessing B") etc. One can straight away use the methods available without being bothered about which data item needs to be synchronized on. 这样,您就不会强迫用户(使用您的类作为API的代码)知道或考虑特定的规则(“如果您正在访问B,则不应修改A”)等。您可以直接使用可用的方法而不必担心哪个数据项需要同步。 Also less documentation ;) 也较少的文档;)

It depends on what intermediate states a client should never see. 这取决于客户永远不会看到的中间状态。

For example, if there is any combination of A and B that is not allowed for the object, then you should synchronize over both accesses: 例如,如果对象不允许使用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;
    }
  }
}

You might want to do that even if A and B are independent from each other: 即使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; }
  }
}

If you do 如果你这样做

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

then a thread might see (1,0), which was never set: this may be acceptable or not, depending on your application. 那么一个线程可能会看到(1,0),但从未设置过:根据您的应用程序,这是否可以接受。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM