簡體   English   中英

Java中如何使用鎖來等待特殊條件?

[英]How to use a lock in Java to wait for the special condition?

我有一個對象:

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 方法來組織它,但是由於中斷而非常危險。
如果我只使用 wait 和 notify 方法,可能會出現無限等待的情況。
如果我們的 wait 方法因某種原因被中斷,我們會檢查“process”變量是否仍然為假,然后我們可以再次使用 wait ,如下所示:

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

使用這樣的代碼是很危險的,因為在我們檢查“!resource.isProcessed()”之后,在我們使用“resource.getLock().wait()”之前,另一個進程可以將“process”設置為true並調用“resource .getLock().notify()”(這不會生效,因為我們還沒有調用“wait()”)。

如何安全地等待某個條件? 如何安全地通知/解鎖某些情況?

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

您可以使用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();
   }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM