简体   繁体   English

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

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

I have an object:我有一个对象:

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

I want to stop the thread "one" untill the thread "two" changes the variable "processed" to true.我想停止线程“一”,直到线程“二”将变量“已处理”更改为真。 After "processed" is set to true I want to wake up the thread "one" and continue doing some stuff.在“已处理”设置为 true 后,我想唤醒线程“一”并继续做一些事情。

I know that we can use wait and notify methods to organize it but it is very dangerous because of interruptions.我知道我们可以使用 wait 和 notify 方法来组织它,但是由于中断而非常危险。
If I will use only wait and notify methods there may be a situation when I wait infinity.如果我只使用 wait 和 notify 方法,可能会出现无限等待的情况。
If our wait method is interrupted by some reason, we check that the "process" variable is still false after that we can use wait again like here:如果我们的 wait 方法因某种原因被中断,我们会检查“process”变量是否仍然为假,然后我们可以再次使用 wait ,如下所示:

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

It is dangerous to use the code like this because after we checked "!resource.isProcessed()" and before we use "resource.getLock().wait()" another process can set the "process" to true and call "resource.getLock().notify()" (which will not take any effect because we haven't yet called "wait()").使用这样的代码是很危险的,因为在我们检查“!resource.isProcessed()”之后,在我们使用“resource.getLock().wait()”之前,另一个进程可以将“process”设置为true并调用“resource .getLock().notify()”(这不会生效,因为我们还没有调用“wait()”)。

How to wait for some condition safely?如何安全地等待某个条件? How to notify/unlock safely some condition?如何安全地通知/解锁某些情况?

As Peter Lawrey answered in comments there are Condition available in java.正如Peter Lawrey在评论中回答的那样,Java 中有可用的Condition (Thank you for pointing) (谢谢指点)

Here is a copy past of the example which is available in the documentation:这是文档中提供的示例的副本:

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

You can use a CountDownLatch to make one thread await until an operation performed by another thread is completed.您可以使用CountDownLatch使一个线程等待,直到另一个线程执行的操作完成。

Let's suppose T1 and T2 are your threads and they share a CountDownLatch initialized with a counter of 1 .假设 T1 和 T2 是您的线程,并且它们共享一个初始化为1的计数器的CountDownLatch T1 will first await() on the latch, while T2 should perform its operation and then invoke countDown() on the latch to let T1 proceed. T1 将首先在闩锁上await() ,而 T2 应执行其操作,然后在闩锁上调用countDown()以让 T1 继续进行。

Of course await() in T1 can still be interrupted, so you may want to call it in a loop.当然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