将一个线程置于hibernate状态,直到另一个线程中的条件得到解决

以下是完成(我认为)同样事情的两个代码块。

我基本上是在尝试学习如何使用Java 1.5的并发来摆脱Thread.sleep(long)。 第一个示例使用ReentrantLock,第二个示例使用CountDownLatch。 我想要做的就是让一个线程进入hibernate状态,直到另一个线程中的条件得到解决。

ReentrantLock提供了一个布尔锁,用于决定是否唤醒另一个线程,然后我使用条件和等待/信号来hibernate另一个线程。 据我所知,我需要使用锁的唯一原因是,如果多个线程需要对boolean的写访问权。

CountDownLatch似乎提供与ReentrantLock相同的function,但没有(不必要的?)锁。 然而,感觉就像我通过初始化它只需要一次倒计时来劫持它的预期用途。 我认为它应该在多个线程要处理同一个任务时使用,而不是在多个线程在等待一个任务时使用。

所以,问题:

  1. 我在ReentrantLock代码中使用锁定“正确的东西”吗? 如果我只在一个线程中写入布尔值,那么锁是否必要? 只要我在唤醒任何其他线程之前重置布尔值我就不会导致问题,我可以吗?

  2. 是否有一个类似于CountDownLatch的类,我可以使用它来避免锁定(假设我应该在这个实例中避免它们),这更适合这个任务?

  3. 有没有其他方法来改进我应该注意的代码?

例1:

import java.util.concurrent.locks.*; public class ReentrantLockExample extends Thread { //boolean - Is the service down? boolean serviceDown; // I am using this lock to synchronize access to sDown Lock serviceLock; // and this condition to sleep any threads waiting on the service. Condition serviceCondition; public static void main(String[] args) { Lock l = new ReentrantLock(); Condition c = l.newCondition(); ReentrantLockExample rle = new ReentrantLockExample(l, c); //Imagine this thread figures out the service is down l.lock(); try { rle.serviceDown = true; } finally { l.unlock(); } int waitTime = (int) (Math.random() * 5000); System.out.println("From main: wait time is " + waitTime); rle.start(); try { //Symbolizes some random time that the service takes to come back up. Thread.sleep(waitTime); } catch (InterruptedException e) { e.printStackTrace(); } //Imagine this thread figures out that the service is back up. l.lock(); try { rle.serviceDown = false; c.signal(); } finally { l.unlock(); } } //Constructor public ReentrantLockExample(Lock l, Condition c) { this.serviceLock = l; this.serviceCondition = c; } /* * Should wait for this imaginary service to come back online. */ public void run() { System.out.println("Thread: start awaiting"); serviceLock.lock(); try { while (isServiceDown()) { serviceCondition.await(); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { serviceLock.unlock(); } System.out.println("Thread: done awaiting"); } private boolean isServiceDown() { return serviceDown; } } 

示例二:

 import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.*; public class CountDownLatchExample extends Thread { //boolean - Is the service down? boolean serviceDown; // I am using this latch to wait on the service. CountDownLatch serviceLatch; public static void main(String[] args) { CountDownLatch cdl = new CountDownLatch(1); CountDownLatchExample cdle = new CountDownLatchExample(cdl); //Service goes down. cdle.serviceDown = true; int waitTime = (int) (Math.random() * 5000); System.out.println("From main: wait time is " + waitTime); cdle.start(); try { //Symbolizes some random time that the service takes to come back up. Thread.sleep(waitTime); } catch (InterruptedException e) { e.printStackTrace(); } //Service comes back up. cdle.serviceDown = false; cdl.countDown(); } //Constructor public CountDownLatchExample(CountDownLatch cdl) { this.serviceLatch = cdl; } /* * Should wait for this imaginary service to come back online. */ public void run() { System.out.println("Thread: start awaiting"); try { while (isServiceDown()) { serviceLatch.await(); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("Thread: done awaiting"); } private boolean isServiceDown() { return serviceDown; } } 

两种方法大致相同,只是CountDownLatch只能释放一次。 之后所有await()调用立即返回。 因此,如果您正在使用可能会出现故障的服务, CyclicBarrier实际上可能更合适。

如果您的情况确实是一次性交易,那么FutureTask会更合适。 您可以调用get()来等待服务变为可用,然后您可以在get()返回后立即使用该服务。

你提到CountDownLatch允许在不使用Locks的情况下等待。 但是,CountDownLatch和ReentrantLock都是使用AbstractQueuedSynchronizer实现的。 在引擎盖下,它们提供相同的同步和可见性语义。

在我看来,锁定/条件变量方法对于此任务更好。 这里有一个类似的例子: http : //java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/locks/Condition.html

响应保护布尔值。 您可以使用volatile( http://www.ibm.com/developerworks/java/library/j-jtp06197.html )。 但是,不使用Locks的问题在于,根据服务停机的时间长短,您将在(isServiceDown())旋转。 通过使用条件等待你告诉操作系统睡眠你的线程,直到虚假的唤醒(在条件的java文档中谈到),或直到条件在另一个线程中发出信号。

完全重新锁定的ASYNC任务示例:

与代码流程模式:

在此处输入图像描述