使一个线程睡眠,直到一个条件在另一个线程中解决 [英] Put one thread to sleep until a condition is resolved in another thread

查看:199
本文介绍了使一个线程睡眠,直到一个条件在另一个线程中解决的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我基本上试图学习如何使用Java 1.5的并发性离开Thread.sleep(long)。第一个示例使用ReentrantLock,第二个示例使用CountDownLatch。



ReentrantLock提供了对布尔值的锁定。我想要做的是让一个线程睡眠,直到另一个线程中的条件解决。使用决定是否唤醒其他线程,然后我使用条件与await /信号睡眠其他线程。据我所知,我需要使用锁的唯一原因是如果多个线程需要写访问布尔。



CountDownLatch似乎提供了与ReentrantLock相同的功能,但没有(不必要的)锁。然而,它感觉像我有点劫持它的预期用途,通过初始化它只需要一个倒计时。我认为应该在多个线程将在同一个任务上工作时使用,而不是当多个线程正在等待一个任务时。



所以,问题: / p>


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


  2. 是否有类似于CountDownLatch的类可以使用避免锁(假设我应该在这种情况下避免他们),这更自然地适合这个任务吗?



示例一:

  import java.util.concurrent.locks。*; 

public class ReentrantLockExample extends Thread {

// boolean - 服务是否关闭?
boolean serviceDown;

//我使用此锁来同步sDown的访问
锁serviceLock;
//和这个条件睡眠任何等待服务的线程。
条件serviceCondition;

public static void main(String [] args){
Lock l = new ReentrantLock();
条件c = l.newCondition();
ReentrantLockExample rle = new ReentrantLockExample(l,c);

//想象这个线程计算出的服务是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 {
//表示服务恢复的一些随机时间。
Thread.sleep(waitTime);
} catch(InterruptedException e){
e.printStackTrace();
}

//想象这个线程计算出服务已经备份。
l.lock();
try {
rle.serviceDown = false;
c.signal();
} finally {
l.unlock();
}

}

//构造函数
public ReentrantLockExample(Lock l,Condition c){
this.serviceLock = l;
this.serviceCondition = c;
}

/ *
*应等待此虚拟服务重新联机。
* /
public void run(){
System.out.println(Thread:start awaiting);
serviceLock.lock();
try {
while(isServiceDown())
{
serviceCondition.await();
}
} catch(InterruptedException e){
// TODO自动生成的catch块
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 - 服务是否关闭?
boolean serviceDown;

//我使用这个锁存器来等待服务。
CountDownLatch serviceLatch;


public static void main(String [] args){
CountDownLatch cdl = new CountDownLatch(1);
CountDownLatchExample cdle = new CountDownLatchExample(cdl);

//服务关闭。
cdle.serviceDown = true;

int waitTime =(int)(Math.random()* 5000);
System.out.println(From main:wait time is+ waitTime);
cdle.start();
try {
//表示服务恢复的一些随机时间。
Thread.sleep(waitTime);
} catch(InterruptedException e){
e.printStackTrace();
}

//服务恢复。
cdle.serviceDown = false;
cdl.countDown();
}

//构造函数
public CountDownLatchExample(CountDownLatch cdl){
this.serviceLatch = cdl;
}

/ *
*应等待此虚拟服务重新联机。
* /
public void run(){
System.out.println(Thread:start awaiting);
try {
while(isServiceDown()){
serviceLatch.await();
}
} catch(InterruptedException e){
// TODO自动生成的catch块
e.printStackTrace();
}
System.out.println(Thread:done awaiting);
}

private boolean isServiceDown(){
return serviceDown;
}
}


解决方案

方法大致相同,但 CountDownLatch 只能释放一次。之后,所有 await() 呼叫立即返回。因此,循环障碍实际上可能



如果您的条件确实是一次性交易,那么 FutureTask 会更合适。您可以致电 get() ,它将等待服务可用,然后您可以在get()返回时立即使用该服务。



您提到CountDownLatch允许等待不使用锁定。但是,CountDownLatch和 ReentrantLock < a>使用 AbstractQueuedSynchronizer a>。在引擎盖下,它们提供相同的同步和可见性语义。


Here are two chunks of code that accomplish (what I think is) the same thing.

I basically am trying to learn how to use Java 1.5's concurrency to get away from Thread.sleep(long). The first example uses ReentrantLock, and the second example uses CountDownLatch. The jist of what I am trying to do is put one thread to sleep until a condition is resolved in another thread.

The ReentrantLock provides a lock on the boolean I'm using to decide whether to wake the other thread or not, and then I use the Condition with await/signal to sleep the other thread. As far as I can tell, the only reason I would need to use locks is if more than one thread required write access to the boolean.

The CountDownLatch seems to provide the same functionality as the ReentrantLock but without the (unnecessary?) locks. However, it feels like I am kind of hijacking its intended use by initializing it with only one countdown necessary. I think it's supposed to be used when multiple threads are going to be working on the same task, not when multiple threads are waiting on one task.

So, questions:

  1. Am I using locks for "the right thing" in the ReentrantLock code? If I am only writing to the boolean in one thread, are the locks necessary? As long as I reset the boolean before waking up any other threads I can't cause a problem, can I?

  2. Is there a class similar to CountDownLatch I can use to avoid locks (assuming I should be avoiding them in this instance) that is more naturally suited to this task?

  3. Are there any other ways to improve this code I should be aware of?

EXAMPLE ONE:

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

EXAMPLE TWO:

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

解决方案

Either approach is roughly equivalent, except that a CountDownLatch can only be released once. After that all await() calls return instantly. So a CyclicBarrier may actually be more appropriate if you are working with a service that may go down and up.

If your condition really is a one-shot deal, then a FutureTask would be more appropriate. You could call get() which would wait for the service to become available, and then you could use the service as soon as get() returns.

You mention that CountDownLatch allows waiting without using Locks. However, both CountDownLatch and ReentrantLock are implemented using AbstractQueuedSynchronizer. Under the hood, they provide identical synchronization and visibility semantics.

这篇关于使一个线程睡眠,直到一个条件在另一个线程中解决的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆