在Java中,相当于JavaScript的setTimeout方法是什么?

63

我需要实现一个函数,在点击按钮后60秒运行。请帮忙,我使用了Timer类,但我认为这不是最好的方法。


这个问题有一些好的相关答案:https://dev59.com/pG855IYBdhLWcg3w_5gQ - intrepidis
9个回答

64

使用JDK1.8实现异步操作:

public static void setTimeout(Runnable runnable, int delay){
    new Thread(() -> {
        try {
            Thread.sleep(delay);
            runnable.run();
        }
        catch (Exception e){
            System.err.println(e);
        }
    }).start();
}

使用Lambda表达式进行调用:

setTimeout(() -> System.out.println("test"), 1000);

使用方法引用也可以:

setTimeout(anInstance::aMethod, 1000);

只处理当前正在运行的线程,请使用同步版本:

public static void setTimeoutSync(Runnable runnable, int delay) {
    try {
        Thread.sleep(delay);
        runnable.run();
    }
    catch (Exception e){
        System.err.println(e);
    }
}

在主线程中使用时要小心 - 这会暂停调用后的所有操作,直到 timeout 过期并且 runnable 执行完毕。


1
是的,不要用这种方式——它会启动太多的线程,我认为使用CompletableFuture技术更好。 - Alexander Mills
1
CompletableFuture仍然会创建一个新的线程。请参见[CompletableFuture.java#2745](https://github.com/netroby/jdk9-dev/blob/a2f7bd42b767c299d0e6cba6f3c5d8f4f32f0874/jdk/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java#L2745)。 - Oleg Mikhailov
1
哎呀,有没有办法告诉CompletableFuture使用线程池而不是每次创建新线程?或者它已经这样做了吗? - Alexander Mills
即使是Java内置的Timer类也会启动“太多线程”:“为线程提供在后台线程中安排将来执行任务的设施。” 我认为这种方式实际上非常干净。它不处理重复执行的情况,但您始终可以让您的任务在结束时再次调用settimeout。 - Pavel Komarov
它并不完全像JavaScript的setTimeout - setTimeout返回可用于通过clearTimeout进行取消的id。 - shabunc

39

使用Java 9的CompletableFuture,非常简单:

CompletableFuture.delayedExecutor(5, TimeUnit.SECONDS).execute(() -> {
  // Your code here executes after 5 seconds!
});

2
代码片段无法运行,显示错误:类型CompletableFuture未定义方法delayedExecutor(int, TimeUnit)。 - Ashish
1
我想我犯了一个错误,这是针对Java 9而不是Java 8的。使用Java 9一切都很好。 - user1079877
1
对于任何使用Java 9及以上版本的人来说,这应该是被接受的答案。 - Jewels

22

“我使用了Timer类,但我认为那不是最好的方法。”

其他回答假设您没有在Swing中使用用户界面(按钮)。

如果您正在使用Swing,则不要使用Thread.sleep(),因为它会冻结您的Swing应用程序。

相反,您应该使用javax.swing.Timer

有关更多信息和示例,请参见Java教程如何使用Swing定时器以及Swing中的并发课程


1
尽管这是被接受的答案,但它已经过时了,特别是自Java 9以来。请参见下面关于“delayedExecutor”的答案。 - Jewels

15

使用java.util.Timer

new Timer().schedule(new TimerTask() {
    @Override
    public void run() {
        // here goes your code to delay
    }
}, 300L); // 300 is the delay in millis

在这里,您可以找到一些信息和示例。


4
谢谢,我也需要一个clearTimeout()的替代方案,使用方法是... Timer timer = new Timer(); timer.schedule(...); timer.cancel(); - mikep
2023年仍然有用。谢谢! - priyamtheone

8

您可以简单地使用 Thread.sleep() 来实现这个目的。但是,如果您正在使用带有用户界面的多线程环境,您将希望在单独的线程中执行此操作,以避免 sleep 阻塞用户界面。

try{
    Thread.sleep(60000);
    // Then do something meaningful...
}catch(InterruptedException e){
    e.printStackTrace();
}

7
请勿使用Thread.sleep,因为这会冻结您的主线程,并且无法模拟JS中的setTimeout。
您需要创建并启动一个新的后台线程来运行代码,而不会停止主线程的执行。
例如:

    new Thread() {
        @Override
        public void run() {
            try {
                this.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            
            // your code here

        }
    }.start();

4
public ScheduledExecutorService = ses;
ses.scheduleAtFixedRate(new Runnable() {
    run() {
            //running after specified time
    }
}, 60, TimeUnit.SECONDS);

它会在scheduleAtFixedRate之后60秒运行。请查看ScheduledExecutorService文档。


你能分享一下你的解决方案比其他方案更好在哪里吗?并且请详细说明你的解决方案是如何工作的,而不仅仅是粘贴一段代码。 - Noel Widmer
代码生成器不是我写的,而是Oracle公司开发的。他们比我更专业,需要详细解释。请参考此链接并阅读文档:https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledExecutorService.html - babak

1
你应该使用Thread.sleep()方法。
try {

    Thread.sleep(60000);
    callTheFunctionYouWantTo();
} catch(InterruptedException ex) {

}

这将等待60,000毫秒(60秒),然后执行您代码中的下一条语句。

1

underscore-java库中有setTimeout()方法。

代码示例:

import com.github.underscore.Underscore;
import java.util.function.Supplier;

public class Main {

    public static void main(String[] args) {
        final Integer[] counter = new Integer[] {0};
        Supplier<Void> incr =
            () -> {
                counter[0]++;
                return null;
            };
        Underscore.setTimeout(incr, 0);
    }
}

该函数将在100毫秒内启动一个新线程。


3
在这种情况下,绝对不应该使用任何形式的“睡眠”(在主线程或活动线程上)。也不需要使用线程。建议使用某种超时机制,如此处所建议的。另外,在超时处理程序中,请确保验证所关心的条件仍然存在!即使在条件不存在时“删除超时”,仍会留下微小的时间差漏洞,您无法完全消除。 - Mike Robinson

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