有条件的等待

时间:2014-03-17 19:11:05

标签: java multithreading thread-safety

我有以下类使用synchronized来尝试阻止对密钥的访问,直到生成密钥为止:

public class KeyManager {

  private String key;

  public KeyManager() {
      genKey();
  }

  private void genKey() {
    new Thread(new Runnable() { 
      synchronized(KeyManager.this) {
        public void run() {
          key = operationThatTakesALongTime();
        }
      }
    }).start();
  }

  synchronized public String getKey() {
    return key;
  }

}

问题是getKey()有时会在内部线程之前被调用,并且它首先抓取锁。

我真正需要的是在getKey()中等待,只有在键为空时才等待。怎么做?

2 个答案:

答案 0 :(得分:3)

MHM

synchronized public long getKey() 
{
    while (key == null) 
    { 
        try 
        { 
            wait(); 
        } 
        catch(InterruptedException e) 
        { 
            /* handle here */ 
        } 
    }
    return key;
}

wait会让线程释放锁,然后在调用notify时再次使用它。如果key仍为null,则会再次释放锁定。

但我认为这不是最好的方法。

抛出InterruptedException

答案 1 :(得分:2)

我会使用CountDownLatch而不是重新实现逻辑。

我也可能避免从构造函数中启动一个新的Thread,因为它可能会导致细微的并发错误 - 相反,您可以简单地将genKey方法设为public并添加相关的javadoc(此方法必须首先调用布拉布拉):

public class KeyManager {

  private volatile boolean genStarted = false;
  private final CountDownLatch keyGenerated = new CountDownLatch(1);
  private String key;

  public void genKey() {
    genStarted = true;
    new Thread(new Runnable() { 
      public void run() {
        key = operationThatTakesALongTime();
        keyGenerated.countDown();
      }
    }).start();
  }

  public String getKey() throws InterruptedException {
    if (!genStarted) throw new IllegalStateException("you must run genKey first");
    keyGenerated.await();
    return key;
  }
}