我的java代码如下所示:
class xHandler
{
private Channel _channel;
// Methods...
void init()
{
_channel = new Channel(...);
synchronized (_channel)
{
// Do some stuff here...e.g.
_channel.send("...");
}
}
}
在其他文件(线程)中我创建了Channel的实例并使用该对象发送了东西,但是只有在上面提到的init方法中我需要它进行同步,没有其他线程应该打开一个通道并发送在此期间的事情。
FindBugs给我一个警告:方法在更新的字段上同步
此方法在从可变字段引用的对象上进行同步。 这不太可能具有有用的语义,因为不同的线程可能在不同的对象上同步。
我怎样才能解决这个问题?是否可以通过简单的测试轻松触发此问题?
答案 0 :(得分:3)
请注意synchronized
正在获取对象的锁定而不是变量!
此方法的每次调用都会锁定另一个对象,因此此处的synchronized块实际上是多余的,因为您在输入init()
时会对其进行修改。
[正如警告所说,不同的线程正在不同的对象上同步]。
如果两个线程同时尝试调用init()
会发生什么?他们两个可能同时进入临界区,这就是你被警告的内容。
要解决此问题,您可能需要将_cahnnel
声明为final
,并在构造函数中初始化它,而不是init()
。
答案 1 :(得分:2)
每次运行方法时,您都会继续创建新锁。因此,你否定了锁定的影响。锁将始终允许新线程进入,因为没有线程在新创建的对象上等待(可能偶尔会有一些race condition
)。每个线程基本上都有自己的锁(而不是共享锁)。
将channel
移到方法之外。
答案 2 :(得分:1)
_channel = new Channel(...);
synchronized (_channel)
我需要它同步,没有其他线程应该打开一个频道和 在此期间发送一些东西。
好像你的代码没有按照你的想法去做。由于您要为每个Channel
实例创建一个新的xHandler
对象,并获取此特定的Channel
锁,因此可以同时运行两个线程。
你真正需要做的是:
Channel
实例同步的特定xHandler
对象(示例:在Channel
构造函数上接收xHandler
的实例,并将其分配给{{ 1}},删除_channel
行,并保持同步代码原样。)_channel = new Channel(...);
上同步,这意味着Channel.class
的两个不同实例永远无法同时使用任何xHandler
。为两个不同的xHandler共享特定Channel
的示例:
Channel