我已经同步了静态getter和setter,如:
public synchronized static int getValue() {
return value;
}
public synchronized static void setValue(int Val) {
value = Val;
}
如果我需要增加值,我会使用像
这样的东西setValue(getValue() + 1);
可能有一个线程设置'值'并立即尝试获取'值'。在这种情况下会发生死锁吗?如果是,那该怎么避免呢?
答案 0 :(得分:5)
可能有一个线程设置'值'并立即尝试获得“价值”。在这种情况下会发生死锁吗?如果是,那该怎么避免呢?
除非涉及两个锁,否则它不会死锁(参见deadlock definition)。但是,当调用get时, 将<{3>},然后调用setter。例如,两个线程可以一个接一个地调用getValue()
值方法,然后返回一个接一个地调用setValue(...)
。然后第二个setter将覆盖另一个setter的增量。
getValue()
等于1 getValue()
等于1 setValue(...)
setValue(...)
醇>
所以答案应该是3,但由于竞争条件,它将是2。
继续使用代码,您需要使用synchronized static void increment()
方法 get,increment和set。您需要synchronized
,因为++
不是原子操作。
public synchronized static int increment() {
value++;
}
所有这些都说,你应该考虑使用AtomicInteger
来代替你处理增量和内存同步的竞争条件。
答案 1 :(得分:1)
synchronized
使用与锁相同的对象(类本身)。所以在这种情况下永远不会发生僵局。
答案 2 :(得分:1)
可能有一个线程设置'值'并立即尝试获取'值'。在这种情况下会发生死锁吗?
没有。出于几个原因。
尝试获取已存在的原始锁时,线程无法死锁。原始锁是可重入的。尝试获取您已经持有的锁定不会阻止。相反,它只是递增锁定中的计数...将通过相应的锁定释放操作递减。
在这种情况下,您甚至不会重新进入锁定状态。执行语句时,首先调用getValue()
获取并释放锁。然后你调用setValue(int)
再次获取和释放锁。如您所见,执行时不会尝试在持有相同锁定时获取锁定。
事实上,死锁(带有原始锁)需要至少两个不同的线程和两个不同的锁。
最后,正如@Gray指出的那样,setValue(getValue() + 1)
不会可靠地增加值...除非你在持有锁时执行该序列。 getValue()
和setValue()
次调用之间有一个时间窗口,其他线程可以更改该值。
答案 3 :(得分:0)
在这种情况下,不需要同步方法,只需将value
变量标记为volatile
volatile private Object var;
但是对于读取 - 修改更新,您必须同步对象,但要注意synchronized方法,因为它接受非null对象引用(不允许使用基元) 所以代码就像这样
volatile static private int value;
public int getValue(){return value;}
public void setValue_direct(int id){value=val;}
public synchronized void setValue_increment(){value++;}
this link可以帮助您解决易失性关键字
答案 4 :(得分:0)
如果需要增加值,请声明单独的synchronized方法。或者使用AtomicInteger而不是int变量(然后不需要同步getter / setter / incrementor)。