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

时间:2012-01-09 10:54:05

标签: java android multithreading synchronized

我正在使用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语句。使用它是否有意义?

2 个答案:

答案 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上的锁,它将看到另一个对象。但是,我确实认为,因为:

  1. this.mailbox全局可见
  2. 引用的分配是原子的
  3. 锁生成围栏
  4. 所有线程应始终具有同步对象的更新视图。