假设我有一个类[X](及其对象[xObject]),并且在其中有两个整数[A]和[B]。我有两个线程一个修改[A],另一个修改[B]。 现在,由于两个线程都改变了[xObject]的值,我应该同步访问[xObject]还是仅仅[A]和[B],因为它们具有不同的内存位置(实际上)。 这个FALL结束的地方,我应该同时访问数组中的两个不同位置,还是在arrayList中访问?
答案 0 :(得分:1)
不确定你对数组等的意思。但如果你改变了两个不同的值而没有在另一个线程中读取它们,则不需要同步。
如果要在线程1中更改变量xObject.a的值并在线程2或其他线程3中读取它,那么除非在类X中创建一个易失性,否则可能会出现过时的读取。
或者使用java.util.concurrent包中的一个同步实用程序。可以谷歌搜索或搜索stackoverflow中的示例。
答案 1 :(得分:1)
如果您有两个独立的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;
}
}
对数组和集合的决定更复杂:如果访问数组元素,但数组本身保持固定,并且数组元素是独立的,则可以跳过同步。但是,如果元素不是独立的,或者集合更复杂(例如,数组列表或哈希表),则需要进行同步,因为集合操作可能会在结构上更改集合,从而破坏一致性。
答案 2 :(得分:1)
如果您的类将在多线程环境中使用,我认为锁定使用getter或public access提供的任何数据是一种很好的做法。
这样您就不会强迫用户(使用您的类作为API的代码)知道或考虑特定规则(“如果您正在访问B,则不应修改A”)等。可以立即使用可用的方法担心需要同步哪个数据项。文档也少;)
答案 3 :(得分:0)
这取决于客户永远不会看到的中间状态。
例如,如果对象不允许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),它从未被设置:这可能是可接受的,取决于你的应用程序。