【问题标题】:How to use a lock in Java to wait for the special condition?如何在 Java 中使用锁来等待特殊条件?
【发布时间】:2016-10-08 13:05:44
【问题描述】:

我有一个对象:

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;
    }
}

我想停止线程“一”,直到线程“二”将变量“已处理”更改为真。在“已处理”设置为 true 后,我想唤醒线程“一”并继续做一些事情。

我知道我们可以使用 wait 和 notify 方法来组织它,但是因为中断很危险。
如果我只使用等待和通知方法,则可能会出现无限等待的情况。
如果我们的等待方法因某种原因被中断,我们检查“进程”变量是否仍然为假,之后我们可以再次使用等待,如下所示:

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

使用这样的代码是危险的,因为在我们检查“!resource.isProcessed()”之后,在我们使用“resource.getLock().wait()”之前,另一个进程可以将“进程”设置为true,并且调用“resource.getLock().notify()”(不会生效,因为我们还没有调用“wait()”)。

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

【问题讨论】:

标签: java multithreading thread-safety locking wait


【解决方案1】:

Peter Lawrey 在 cmets 中回答了 Condition 在 java 中可用。 (谢谢指点)

这是文档中提供的示例的副本:

 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();
     }
   }
 }

【讨论】:

    【解决方案2】:

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

    假设 T1 和 T2 是您的线程,它们共享一个使用 1 计数器初始化的 CountDownLatch。 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();
       }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-07-05
      • 2019-10-31
      • 2015-07-12
      • 2015-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多