使用synchronized关键字时Java应用程序停滞不前

时间:2012-02-19 06:10:51

标签: java multithreading concurrency synchronized

我有一个开始几个线程的类。每个线程(扩展线程)调用类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)

由于

2 个答案:

答案 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