我有一个开始几个线程的类。每个线程(扩展线程)调用类WH的新实例,类WH具有将在所有线程之间共享的变量。层次结构如下:
class S extends Thread {
....
....
WH n = new WH(args);
....
....
}
现在,WH类有一个要共享的变量,声明为:
private static volatile Integer size;
One of the functions tries to access size through Synchronized:
Synchronized (size) { // Program gets stuck at this line
... stuff ...
}
即使我只生成一个线程,它也会卡住。知道为什么会这样吗? (仅供参考 - 我不想根据我的设计选择使用AtomicInteger)
由于
答案 0 :(得分:2)
您的问题是锁定非最终变量引用具有无用的语义。
只要您看到某个synchronized(var);
和var
的内容是实例或静态变量并且未标记为final
,那么这是一个错误,因为任何事情都可能出现并且做一个var = new Thing();
,现在至少有2个线程可以同时对该块进行操作,这是一个逻辑错误,没有例外。每个Java lint样式检查器都将此标记为严重错误,只是因为编译器没有发现这并不意味着它在任何情况下都有用。
在这种情况下,您通过更改不可变Integer
类的值来公开这些无用的语义。
您的Integer
变量size
不是最终版,而Immutable
表示每次更改时,都必须将参考更改为新对象表示新值,每个线程都会获得新和不同引用以锁定。因此没有锁定。
使用private static final AtomicInteger size = new AtomicInteger();
然后你可以synchronize(size);
,因为size
现在是final
你可以在适当的位置改变它并获得预期和正确的语义。
或者您可以synchronize(some_other_final_reference);
并使用常规int
,只要同步的引用是final
,并且可以在任何需要获取句柄的线程的范围内它,它会工作。
就我个人而言,我会使用AtomicInteger
它更具凝聚力,你可以锁定你不想改变的任何其他线索,自我记录和明确的意图。
答案 1 :(得分:1)
我无法使用AtomicInteger,因为我需要获取size的值, 检查条件,并根据条件增加或不增加。 所以我必须做一个可能的增量。我还需要 在这种情况下锁定。
我相信你所描述的是AtomicInteger绝对可以做到的,没有锁定,通过compareAndSet()
方法,不是吗?虽然唯一受支持的测试是平等,但也许这对你不起作用。
此外,如果您计划同步变量,则无需另外设置volatile
。