为什么"等待"保持多个锁时不应该调用它?

时间:2018-05-24 13:11:30

标签: java multithreading concurrency synchronization

  public synchronized void methodOne(List<String> profileNames, ParameterAttributes parameterAttributes) throws InterruptedException {

    if (profileNames != null && !profileNames.isEmpty()) {
      profileNames.forEach(profileName -> System.out.println(profileName));
    }
    synchronized(lockObj) {
      lockObj.wait();
    }
  }

这里我们有了synchronized方法,并且在方法内部我再次调用了wait方法的同步块。

2 个答案:

答案 0 :(得分:0)

好吧,当你的线程等待通知时,它仍然保留其他锁,大大增加了死锁的可能性。

看起来您的代码拥有三个对象监视器:

  • methodOne所属的对象,因为它是同步的
  • lockObj,因为你正在同步它
  • parameterAttributes因为你正在等待它

您的代码是否会抛出IllegalMonitorStateException?我问,因为在代码示例中它并不明显它实际上拥有parameterAttributes的监视器(代码示例中没有synchronized(parameterAttributes))。

无论如何,我认为你需要简化。拥有如此多的监视器似乎过于复杂。通常你只需要策略,同步方法或lockObj来保护一些可变状态,而不是两者。另外,我建议调查像Akka这样的演员框架。

答案 1 :(得分:0)

考虑制作profileNames的本地副本,然后在执行任何I / O之前释放锁:

public void methodOne(
    List<String> profileNames, 
    ParameterAttributes parameterAttributes
) throws InterruptedException 
{
    if (profileNames != null && !profileNames.isEmpty()) {
        List<String> localNames;

        synchronized (this) {
            localNames = new ArrayList<>(profileNames);
        }
        localNames.forEach(profileName -> System.out.println(profileName));
    }

    synchronized(lockObj) {
        parameterAttributes.wait();  //NOTE: Wrong way to use wait(), but that's a topic
    }                                //      for another question.
}

有时,在为多处理器平台编写多线程代码时,您必须改变对有效率和低效率的想法。在单线程代码中,复制列表效率很低,但是在执行I / O之前通过释放锁可能获得的性能提升可能远远大于通过制作副本所获得的命中率。