使用synchronized关键字时Java应用程序卡住
我有一个启动几个线程的类。每个线程(扩展Thread)调用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)
谢谢
I have a class that starts a few threads. Each thread (extends Thread) calls a new instance of class WH, class WH has a variable that is to be shared among all threads. So the hierarchy looks like:
class S extends Thread {
....
....
WH n = new WH(args);
....
....
}
Now class WH has a variable that is to be shared, declared as:
private static volatile Integer size;
One of the functions tries to access size through Synchronized:
Synchronized (size) { // Program gets stuck at this line
... stuff ...
}
It gets stuck even if I spawn off just one thread. Any idea why this is happening? (FYI- I do not want to use AtomicInteger based on my design choices)
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您的问题是锁定非最终变量引用具有无用的语义。
每当您看到某些内容正在执行
synchronized(var);
且var
是实例或静态变量且未标记为final
时,它就是一个错误,因为任何东西都可以执行var = new Thing();
并且现在至少有 2 个线程可以同时操作该块,这是一个逻辑错误,没有例外。每个 Java lint 样式检查器都会将此标记为严重错误,仅仅因为编译器没有捕获此错误并不意味着它在任何情况下都有任何用处。在这种情况下,您通过更改不可变的
Integer
类的值来暴露这些无用的语义。您的
Integer
变量size
不是最终的并且是不可变的
,这意味着每次更改它时您必须更改引用 到代表新值的新对象,每个线程都会获得一个new和不同引用来锁定。因此没有锁定。使用
private static Final AtomicInteger size = new AtomicInteger();
然后您可以
synchronize(size);
因为size
现在是Final
您可以就地改变它并获得预期的正确语义。或者您可以
synchronize(some_other_final_reference);
并使用常规int
,只要同步的引用是final
并且可以在范围内任何需要获取它的句柄的线程,它都会工作。就我个人而言,我会使用 AtomicInteger,这样更有凝聚力,您可以锁定您不希望被任何其他线程更改的内容,自记录和明确的意图。
Your problem is that locking on a Non-Final variable reference has useless semantics.
Anytime you see something doing a
synchronized(var);
andvar
is an instance or static variable and isn't markedfinal
, it is an error, because anything can come along and do avar = new Thing();
and now there are at least 2 threads that can operate on that block at the same time, this is a logical error no exceptions. Every Java lint style checker flags this as a critical error, just because the compiler doesn't catch this doesn't mean it has any usefulness in any case.In this case, you are exposing these useless semantics by changing the value of the immutable
Integer
class.Your
Integer
variablesize
is non-Final and isImmutable
which means every time you change it you must change the reference to the new object that represents the new value and every thread will get a new and different reference to lock onto. Thus no locking.Use a
private static final AtomicInteger size = new AtomicInteger();
And then you can
synchronize(size);
sincesize
is nowfinal
you can mutate it in place and get the intended and correct semantics.or you can
synchronize(some_other_final_reference);
and use a regularint
as long as that reference that is synchronized on isfinal
and can be in scope of any thread that needs to acquire a handle to it, it will work.Personally I would use the
AtomicInteger
it is more cohesive that way, you are locking on what you don't want changing by any other thread, self-documenting and clear intentions.我相信您所描述的是 AtomicInteger 绝对可以通过
compareAndSet()
方法完成的事情,而不需要锁定,不是吗?虽然唯一支持的测试是平等,所以也许这对你不起作用。另外,如果您计划同步变量,则无需将其设置为
易失性
。I believe what you are describing is something that AtomicInteger can definitely do, without locking, via the
compareAndSet()
method, no? Though the only supported test is equality, so maybe that won't work for you.Also, if you are planning on synchronizing on the variable, then there is no need to also make it
volatile
.