繁体   English   中英

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

[英]Multithreaded correctness: Using synchronized block

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

synchronized块“捕获”给定对象的锁,在您的情况下为mailbox表示的对象。 将变量mailbox更改为指向其他对象后,其他线程可以“捕获”此对象的锁定而不会出现问题,因为它不会被捕获。

请注意,锁定用于对象,而不是用于引用!

现在,concider以下[伪代码]:

synchronised (myObject) { 
  myObject = new Object();
  i += 5; //assume i is an instance variable
}

实际上这里没有锁! 每个线程都在锁定块中创建一个新对象,并且i的修改不同步!

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

synchronized (this.mailbox) {
    this.mailbox.wait();        
}

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

您的代码检查员可能会被该行混淆:

this.mailbox = Event.START;

意味着你可能同时修改这个对象,这样如果另一个线程试图获取this.mailbox上的锁,它将看到一个不同的对象。 但是,我确实认为,因为:

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM