如何在Java中使用锁来等待特殊条件?

时间:2016-10-08 13:05:44

标签: java multithreading thread-safety locking wait

我有一个对象:

public class Resource {
    private Lock lock = new ReentrantLock();
    private boolean processed = false;

    public Lock getLock() {
        return lock;
    }

    public boolean isProcessed() {
        return processed;
    }

    public void setProcessed(boolean processed) {
        this.processed = processed;
    }
}

我想停止线程"一个"直到线程"两个"更改变量"已处理"为真。经过"处理后#34;设置为true我想唤醒线程"一个"并继续做一些事情。

我知道我们可以使用wait和notify方法来组织它,但由于中断而非常危险。
如果我只使用等待和通知方法,那么当我等待无穷大时可能会出现这种情况 如果我们的等待方法因某种原因而中断,我们会检查"进程"变量仍然是假的,之后我们可以像这样再次使用等待:

while(true){
    if(!resource.isProcessed()){
       resource.getLock().wait();
    }
    else{
       break;
    }
}

使用这样的代码是危险的,因为在我们检查了"!resource.isProcessed()"在我们使用" resource.getLock()。wait()"之前另一个过程可以设置"过程"为true并调用" resource.getLock()。notify()" (这不会产生任何影响,因为我们还没有调用" wait()")。

如何安全地等待某些情况?如何安全地通知/解锁某些条件?

2 个答案:

答案 0 :(得分:0)

您可以使用CountDownLatch使一个线程等待,直到另一个线程执行的操作完成。

假设T1和T2是您的主题,并且他们共享CountDownLatch,并使用1计数器进行初始化。 T1将在锁存器上首先await(),而T2应执行其操作,然后在锁存器上调用countDown()以使T1继续运行。

当然,T1中的await()仍可能被中断,因此您可能希望在循环中调用它。

class T1 implements Runnable {
   private final CountDownLatch latch;

   T1(CountDownLatch latch) {
     this.latch = latch;
   }

   public void run() {
      awaitUninterruptibly(latch);
      doWork();
   }

   private void awaitUninterruptibly(CountDownLatch latch) {
      boolean interrupted = false;
      try {
         while (true) {
            try {
               latch.await();
               return;
            } catch (InterruptedException e) {
               interrupted = true;
            }
         }
      } finally {
         if (interrupted) {
            Thread.currentThread().interrupt();
         }
      }
   }
}

class T2 implements Runnable {
   private final CountDownLatch latch;

   T1(CountDownLatch latch) {
      this.latch = latch;
   }

   public void run() {
      doWork();
      latch.countDown();
   }
}

答案 1 :(得分:0)

正如Peter Lawrey在评论中回答的那样,java中有Condition。 (谢谢你的指点)

以下是文档中提供的示例的复制过程:

 class BoundedBuffer {
   final Lock lock = new ReentrantLock();
   final Condition notFull  = lock.newCondition(); 
   final Condition notEmpty = lock.newCondition(); 

   final Object[] items = new Object[100];
   int putptr, takeptr, count;

   public void put(Object x) throws InterruptedException {
     lock.lock();
     try {
       while (count == items.length)
         notFull.await();
       items[putptr] = x;
       if (++putptr == items.length) putptr = 0;
       ++count;
       notEmpty.signal();
     } finally {
       lock.unlock();
     }
   }

   public Object take() throws InterruptedException {
     lock.lock();
     try {
       while (count == 0)
         notEmpty.await();
       Object x = items[takeptr];
       if (++takeptr == items.length) takeptr = 0;
       --count;
       notFull.signal();
       return x;
     } finally {
       lock.unlock();
     }
   }
 }