如何让Java中的一个线程休眠特定的时间?

14

我有一个场景,想让线程睡眠一段特定的时间。

代码:

    public void run(){
        try{
            //do something
                     Thread.sleep(3000);
//do something after waking up
                }catch(InterruptedException e){
                // interrupted exception hit before the sleep time is completed.so how do i make my thread sleep for exactly 3 seconds?
                }
        }

现在我该如何处理我尝试运行的线程在休眠完成之前遇到中断异常的情况?同时,当线程被中断后会醒来吗?它会进入可运行状态吗?还是只有在进入可运行状态后才会流向catch块?

5个回答

10

当您的线程被中断时,它会进入 InterruptedException 异常块。然后您可以检查线程休眠的时间,并计算出还需休眠多少时间。最后,除了吞噬异常外,恢复中断状态也是良好的实践,以便调用堆栈中更高层的代码可以处理它。

public void run(){

    //do something

    //sleep for 3000ms (approx)     
    long timeToSleep = 3000;
    long start, end, slept;
    boolean interrupted;

    while(timeToSleep > 0){
        start=System.currentTimeMillis();
        try{
            Thread.sleep(timeToSleep);
            break;
        }
        catch(InterruptedException e){

            //work out how much more time to sleep for
            end=System.currentTimeMillis();
            slept=end-start;
            timeToSleep-=slept;
            interrupted=true
        }
    }

    if(interrupted){
        //restore interruption before exit
        Thread.currentThread().interrupt();
    }
}

这是一种清晰的做法,我想。但作为非英语母语者,我在设置interrupt()之后遇到了困难。对我来说,它的意思是,当发生InterruptedException时,请记住它发生了。最后一件事是,如果发生中断,则“执行中断”。对我来说,更有意义的是Thread.currentThread().uninterrupt(),因为中断已经发生了 - 好吧,uninterrupt()不存在。我在理解整个问题方面犯了什么错误? - Dirk Schumacher

1
  1. 根据我的经验,使用Sleep通常是为了弥补程序中其他地方的错误时机,需要重新考虑!
  2. 尝试这个:

    public void run(){
            try{
                //做一些事情
                long before = System.currentTimeMillis();
                Thread.sleep(3000);
                //唤醒后再做一些事情
            }catch(InterruptedException e){
                long diff = System.currentTimeMillis()-before;
                //这只是一个近似值!异常处理程序也需要时间....
                if(diff < 3000)
                    //做其他事情,也许回去睡觉。
                    //在睡眠时间完成之前被中断异常击中。那么如何让线程精确地睡眠3秒钟呢?
            }
    }
    
  3. 如果您没有自己中断睡眠,为什么会唤醒此线程?看起来您正在做一些非常错误的事情...


中断可以来自外部事件,例如操作系统的“优雅关闭”请求。 - Tony Ennis
@Tony:原理是一样的。中断仍然表示有意取消线程的请求,而不是像OP的措辞似乎暗示的那样,线程被“撞击”了。 - Nathan Hughes

1
根据此页面,您需要编写代码以使其按照您的意愿运行。如果使用上面的线程,您的睡眠将被中断并且您的线程将退出。理想情况下,您应该重新抛出异常,以便启动线程的任何内容都可以采取适当的措施。
如果您不希望发生这种情况,您可以将整个过程放入while(true)循环中。现在,当中断发生时,睡眠被中断,您吃掉异常,并循环开始新的睡眠。
如果您想完成3秒的睡眠,您可以通过有10个300毫秒的睡眠来近似它,并将循环计数器保持在while循环之外。当您看到中断时,吃掉它,设置一个“我必须死”的标志,并继续循环直到您睡够了。然后以受控方式中断线程。
以下是一种方法:
public class ThreadThing implements Runnable {
    public void run() {
        boolean sawException = false;
        for (int i = 0; i < 10; i++) {
            try {
                //do something
                Thread.sleep(300);
                //do something after waking up
            } catch (InterruptedException e) {
                // We lose some up to 300 ms of sleep each time this
                // happens...  This can be tuned by making more iterations
                // of lesser duration.  Or adding 150 ms back to a 'sleep
                // pool' etc.  There are many ways to approximate 3 seconds.
                sawException = true;
            }
        }
        if (sawException) Thread.currentThread().interrupt();
    }
}

1
我是一个有用的助手,可以翻译文本。
我会这样使用它:
因此,没有必要等待特定的时间来结束。
public void run(){

    try {

        //do something

        try{Thread.sleep(3000);}catch(Exception e){}

        //do something

    }catch(Exception e){}

}

有可能等待/休眠3秒钟而没有任何人/任何事情注意到。我不会点赞这个答案。 - Dirk Schumacher

1

你为什么想要睡眠恰好3秒钟?如果只是需要在一段时间后执行某些操作,可以尝试使用计时器


计时器可能更好,但它会引入潜在的竞争和并发问题,而只是休眠可以避免这些问题。然而,我认为使用计时器值得学习。 - locka
上面的计时器链接似乎已经失效了。 - AkD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接