我正在使用CMU Sphinx语音识别器库(Link to source)来使用synchronized
块。
RecognizerTask中的一个示例块:
Event mailbox;
[...]
public void start() {
synchronized (this.mailbox) {
this.mailbox.notifyAll();
this.mailbox = Event.START;
}
}
代码工作没有任何问题,但BugFinder会发出此警告:
错误:在RecognizerTask.mailbox上进行同步是徒劳的尝试 保护它
此方法在一个看起来像是的字段上同步 试图防止同时更新该字段。但 保护一个字段会锁定引用的对象,而不是锁定 领域。这可能无法提供您需要的互斥,以及其他 线程可能正在获取引用对象上的锁(对于其他对象) 目的)。这种模式的一个例子是:
private Long myNtfSeqNbrCounter = new Long(0); private Long getNotificationSequenceNumber() { Long result = null; synchronized(myNtfSeqNbrCounter) { result = new Long(myNtfSeqNbrCounter.longValue() + 1); myNtfSeqNbrCounter = new Long(result.longValue()); } return result; }
说实话,我不太了解错误描述,在这种情况下应该是错误的。 全局变量不是字段吗?如果没有,我该如何改进代码?
/ edit:这是调用Event.wait()
的唯一部分:
Event todo = Event.NONE;
synchronized (this.mailbox) {
todo = this.mailbox;
/* If we're idle then wait for something to happen. */
if (state == State.IDLE && todo == Event.NONE) {
try {
//Log.d(getClass().getName(), "waiting");
this.mailbox.wait();
todo = this.mailbox;
//Log.d(getClass().getName(), "got" + todo);
} catch (InterruptedException e) {
/* Quit main loop. */
//Log.e(getClass().getName(), "Interrupted waiting for mailbox, shutting down");
todo = Event.SHUTDOWN;
}
}
/* Reset the mailbox before releasing, to avoid race condition. */
this.mailbox = Event.NONE;
}
此代码实际上也使用synchronized
语句。使用它是否有意义?
答案 0 :(得分:3)
synchronized块“捕获”给定对象的锁,在您的情况下为mailbox
表示的对象。一旦你将变量mailbox
更改为指向另一个对象,其他线程就可以“捕获”该对象的锁定而不会出现问题,因为它没有被采用。
请注意,锁定用于对象,而不是用于引用!
现在,使用以下[伪代码]:
synchronised (myObject) {
myObject = new Object();
i += 5; //assume i is an instance variable
}
实际上这里没有锁!每个线程都在锁定块中创建一个新对象,并且i的修改不同步!
答案 1 :(得分:3)
我不认为它适用于您的情况。你有一个notifyAll()
的调用,这意味着在其他线程的代码中某处有一个匹配的wait()
调用:
synchronized (this.mailbox) {
this.mailbox.wait();
}
意味着另一个线程在等待通知时放弃锁定。
你的代码检查员可能会对这一行感到困惑:
this.mailbox = Event.START;
意味着您可能同时修改此对象,这样如果另一个线程试图获取this.mailbox
上的锁,它将看到另一个对象。但是,我确实认为,因为:
this.mailbox
全局可见所有线程应始终具有同步对象的更新视图。