多线程正确性:使用同步块

For*_*rce 6 java multithreading android synchronized

我正在使用CMU Sphinx语音识别器库(Link to source)来使用synchronized块.

来自RecognizerTask的一个示例块:

Event mailbox;

[...]

public void start() {
    synchronized (this.mailbox) {
        this.mailbox.notifyAll();
        this.mailbox = Event.START;
    }
}
Run Code Online (Sandbox Code Playgroud)

代码工作没有任何问题,但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;
 }
Run Code Online (Sandbox Code Playgroud)

说实话,我不太了解错误描述,在这种情况下应该是错误的.全局变量不是字段吗?如果没有,我该如何改进代码呢?

/ 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;
        }
Run Code Online (Sandbox Code Playgroud)

此代码实际上也使用了一个synchronized语句.使用它是否有意义?

Tud*_*dor 3

我认为这不适用于你的情况。您有一个调用notifyAll(),这意味着其他线程的代码中的某个地方有一个匹配的wait()调用:

synchronized (this.mailbox) {
    this.mailbox.wait();        
}
Run Code Online (Sandbox Code Playgroud)

这意味着另一个线程将在等待通知时放弃锁。

您的代码检查器可能会对以下行感到困惑:

this.mailbox = Event.START;
Run Code Online (Sandbox Code Playgroud)

这意味着您可能会同时修改此对象,这样如果另一个线程尝试获取 的锁this.mailbox,它将看到另一个对象。然而,我确实认为,因为:

  1. this.mailbox是全球可见的
  2. 引用的分配是原子的
  3. 锁生成栅栏

所有线程都应始终具有同步对象的更新视图。