"长监视器争用事件"的问题是什么?

时间:2017-01-21 23:26:21

标签: android java-threads

我有以下服务代码,我在其中启动了一个负责调度消息的线程。

       public void run() {
          while (! Thread.interrupted()) {
            try {
              Message msg = null;
              synchronized (_queue) {
                if (_queue.size() == 0) {
                  _queue.wait(10000);
                }

                if (_queue.size() != 0) {
                  msg = _queue.poll();
                }

                if (msg != null) {
                  _dispatcher.dispatch(msg);
                }
              }
            }
            catch (InterruptedException i) {                }
            catch (Exception e) {                }
          }
      }
  public void add (final Message m){
    if (m == null)
      return;
    synchronized (_queue){
      _queue.add(m);
      _queue.notify();
    }
  }

但是当这个代码在我的android模拟器上运行时,我收到了很多警告,如下所示:

Long monitor contention event with owner method=void com.foo.PrioritizedMessageQueue.run() from PrioritizedMessageQueue.java:58 waiters=0 for 585ms

对我而言,这似乎是编写队列处理器的最有效方式。当没有要处理的消息时,处理线程将等待,直到添加一个消息,并且"添加"将通知任何等待的线程为什么将新消息添加到队列中。我的想法是当没有消息存在时(因为它被阻止),调度线程不会使用最少的资源。

然而,有一个原因是android发出这个警告,但我想知道为什么。很明显我的线程被阻止了很长时间,但为什么这是一个问题呢?这不是更高效,因为它在等待时不会使用任何CPU周期吗?

另外,我是否应该担心android可能会因为被阻止太久而杀死我的帖子?我讨厌我的线程被杀,但不是服务。如果我的服务被杀了,我可以处理,但我无法处理被杀死的一个线程。

1 个答案:

答案 0 :(得分:2)

在调用_dispatcher.dispatch之前,您应该释放队列上的锁。否则,当工作线程正在处理消息时,阻止尝试调用_queue.add的外部线程。

只需调整花括号即可。这里调整了run线程函数,以便在放弃dispatch的监视器后调用_queue

   public void run() {
      while (! Thread.interrupted()) {
        try {
          Message msg = null;
          synchronized (_queue) {     // acquire the queue lock
            if (_queue.size() == 0) {
              _queue.wait(10000);
            }

            if (_queue.size() != 0) {
              msg = _queue.poll();
            }
          }                           // release the queue lock

          if (msg != null) {
            _dispatcher.dispatch(msg);
          }
        }
        catch (InterruptedException i) {
        }
        catch (Exception e) {
        }
      }
  }