当前位置: 首页 > 面试题库 >

让一个线程进入睡眠状态,直到另一个线程解决了问题

相德宇
2023-03-14
问题内容

这里有两个代码块完成(我认为是)同一件事。

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

ReentrantLock在我用来确定是否唤醒另一个线程的布尔值上提供了一个锁,然后我将Condition与await /
signal一起使用来使另一个线程休眠。据我所知,我需要使用锁的唯一原因是是否需要多个线程对布尔值进行写访问。

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

所以,问题:

  1. 我是否在ReentrantLock代码中将锁用于“正确的事情”?如果仅在一个线程中写入布尔值,是否需要锁?只要我在唤醒任何其他线程之前重设布尔值就不会造成问题,可以吗?

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

  3. 还有什么其他方法可以改善我应注意的代码?

示例一:

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允许不使用锁而等待。但是,CountDownLatch和ReentrantLock都是使用AbstractQueuedSynchronizer实现的。在幕后,它们提供了相同的同步和可见性语义。



 类似资料:
  • 问题内容: 我有产生新线程的执行主线程。在main()的执行主线程中,我正在调用。何时获得 未处理的异常 类型? 我不确定为什么会得到这个。我以为这是因为我需要对主线程的引用,所以我继续并通过进行了引用。 这不是让线程休眠的方法吗?我需要做的是让主线程等待/睡眠/延迟,直到它再次需要工作为止。 问题答案: 您看到的是编译错误,原因是您没有正确处理检查的异常(在这种情况下)。处理意味着执行以下操作之

  • 问题内容: 这会使当前的UI线程休眠吗? 问题答案: 如果要在ui线程上调用sleep,它将阻塞ui线程。不要在ui线程上调用sleep。您不应该阻止ui线程。 http://developer.android.com/reference/java/lang/Thread.html http://docs.oracle.com/javase/tutorial/essential/concurren

  • 我正在我的UI线程中调用一个方法。在这个方法中创建了一个新线程。我需要UI线程等待这个新线程完成,因为我需要这个线程的结果来继续UI线程中的方法。但我不想让UI在等待时冻结。有没有办法让UI线程在不忙的情况下等待?。

  • 我使用 C 和 POSIX 线程创建了一个多线程应用程序。我现在应该阻塞一个线程(主线程),直到设置了布尔标志(变为真)。 我找到了两种方法来完成这件事。 > 在没有睡眠的情况下旋转。 在睡眠中旋转循环。 如果我应该遵循第一种方式,为什么有些人编写代码遵循第二种方式?如果应该使用第二种方法,为什么要让当前线程Hibernate呢?这种方式的缺点是什么?

  • 我如何启动两个线程,其中thread1首先执行,thread2在thread1结束时启动,而主方法线程可以在不锁定其他两个线程的情况下继续工作? 我尝试了join(),但是它需要从线程调用,线程必须等待另一个线程,没有办法执行类似thread2.join(thread1)的操作;因此,如果我在main()中调用join,我将有效地停止主线程的执行,而不仅仅是Thread2的执行。 #编辑:为什么我

  • 问题内容: 我在Java中的线程上有些挣扎,我有三个线程- 线程1,线程2和线程3。那些启动时正在执行某些任务,我想通过thread1停止这两个线程。我将thread1放在,然后停止两个线程,但是两个线程的进程仍在运行。你有什么想法吗? 问题答案: 您如何试图阻止他们??警告此方法已弃用。 而是考虑对线程1使用某种标志来与线程2和3通信,它们应该停止。实际上,您可能会使用interrupts。 下