java:在特定秒数后运行函数

Posted

技术标签:

【中文标题】java:在特定秒数后运行函数【英文标题】:java: run a function after a specific number of seconds 【发布时间】:2011-01-16 12:22:24 【问题描述】:

我有一个特定的功能,我想在 5 秒后执行。 我如何在 Java 中做到这一点?

我找到了 javax.swing.timer,但我真的不明白如何使用它。看起来我正在寻找比这个类提供的更简单的东西。

请添加一个简单的使用示例。

【问题讨论】:

您是要等待 5 秒然后执行某项操作,还是要在 5 秒内继续执行其他操作? 我想继续做其他事情 【参考方案1】:
new java.util.Timer().schedule( 
        new java.util.TimerTask() 
            @Override
            public void run() 
                // your code here
            
        , 
        5000 
);

编辑:

javadoc 说:

在对 Timer 对象的最后一个实时引用消失并且所有未完成的任务都已完成执行后,计时器的任务执行线程将正常终止(并成为垃圾回收的对象)。但是,这可能需要任意长的时间。

【讨论】:

如果您运行该代码,您将泄漏线程。完成后请务必清理计时器。 @skaffman:我添加了来自 javadoc 的声明。你真的需要在调用日程后清理吗? 可能没问题,但后来可能不行。如果您多次运行该代码片段,您将有松散的线程在乱跑,无法整理它们。 import java.util.Timer; import java.util.TimerTask; 可能会更明显地表明这不是javax.swing.Timer。 / 注意,如果您使用的是 Swing(实际上是 AWT),您不应该做任何事情来更改非事件调度线程 (EDT) 线程上的组​​件(java.util.Timer 任务不好;javax.swing.Timer 操作好)。 @PaulAlexander 根据文档 - 在 run 方法结束时调用 timer 的 cancel 方法将清除 TimerTasks 的执行线程。【参考方案2】:

类似这样的:

// When your program starts up
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();

// then, when you want to schedule a task
Runnable task = ....    
executor.schedule(task, 5, TimeUnit.SECONDS);

// and finally, when your program wants to exit
executor.shutdown();

Executor 上还有各种其他工厂方法,如果您希望池中有更多线程,您可以使用它们。

请记住,完成后关闭执行程序很重要。当最后一个任务完成时,shutdown() 方法将干净地关闭线程池,并阻塞直到发生这种情况。 shutdownNow() 将立即终止线程池。

【讨论】:

shutdown() 不会阻止。 awaitTermination() 会。 shutdown() 只是不允许提交新任务。 shutdownNow() 也会中断任务(不一定立即终止)。【参考方案3】:

javax.swing.Timer使用示例

Timer timer = new Timer(3000, new ActionListener() 
  @Override
  public void actionPerformed(ActionEvent arg0) 
    // Code to be executed
  
);
timer.setRepeats(false); // Only execute once
timer.start(); // Go go go!

此代码只会执行一次,执行时间为 3000 毫秒(3 秒)。

正如 camickr 所提到的,您应该查找“How to Use Swing Timers”以获取简短介绍。

【讨论】:

就这样去吧去吧! :-) 工作就像一个魅力!我认为这是最有效的方式。【参考方案4】:

作为@tangens 答案的变体:如果您不能等待垃圾收集器清理您的线程,请在运行方法结束时取消计时器。

Timer t = new java.util.Timer();
t.schedule( 
        new java.util.TimerTask() 
            @Override
            public void run() 
                // your code here
                // close the thread
                t.cancel();
            
        , 
        5000 
);

【讨论】:

不应该将Timer t 声明为final,因为它是在内部类中访问的? @JoshuaPinter 是的,它应该被声明为 final,但至少在 Java 8 中不需要明确声明为 final。它只需要“有效地最终”(javarevisited.blogspot.com/2015/03/…)【参考方案5】:

我的代码如下:

new java.util.Timer().schedule(

    new java.util.TimerTask() 
        @Override
        public void run() 
            // your code here, and if you have to refresh UI put this code: 
           runOnUiThread(new   Runnable() 
                  public void run() 
                            //your code

                        
                   );
        
    , 
    5000 
);

【讨论】:

【参考方案6】:

您最初的问题提到了“Swing Timer”。如果实际上您的问题与 SWing 有关,那么您应该使用 Swing Timer 而不是 util.Timer。

阅读 Swing 教程中关于“How to Use Timers”的部分以获取更多信息。

【讨论】:

【参考方案7】:

你可以使用 Thread.Sleep() 函数

Thread.sleep(4000);
myfunction();

您的函数将在 4 秒后执行。但是,这可能会暂停整个程序...

【讨论】:

而且它只保证执行将在 4 秒后运行,这也可能意味着 10 秒后! questzen,你会发现这里的所有方法都是这样做的。事实上,即使您在操作系统级别安排某些事情,您通常也只能保证事件之前的最短经过时间。 这不是真正的问题 我只需要投反对票 - 根本没有回答手头的问题。 OP 在评论中说“我想继续做其他事情”;这段代码显然不是。【参考方案8】:

所有其他 unswer 都需要在新线程中运行您的代码。 在一些简单的用例中,您可能只想稍等片刻,然后在同一个线程/流中继续执行。

下面的代码演示了该技术。请记住,这类似于 java.util.Timer 在底层所做的工作,但更轻量级。

import java.util.concurrent.TimeUnit;
public class DelaySample 
    public static void main(String[] args) 
       DelayUtil d = new DelayUtil();
       System.out.println("started:"+ new Date());
       d.delay(500);
       System.out.println("half second after:"+ new Date());
       d.delay(1, TimeUnit.MINUTES); 
       System.out.println("1 minute after:"+ new Date());
    

DelayUtil 实现

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class DelayUtil 
    /** 
    *  Delays the current thread execution. 
    *  The thread loses ownership of any monitors. 
    *  Quits immediately if the thread is interrupted
    *  
    * @param duration the time duration in milliseconds
    */
   public void delay(final long durationInMillis) 
      delay(durationInMillis, TimeUnit.MILLISECONDS);
   

   /** 
    * @param duration the time duration in the given @code sourceUnit
    * @param unit
    */
    public void delay(final long duration, final TimeUnit unit) 
        long currentTime = System.currentTimeMillis();
        long deadline = currentTime+unit.toMillis(duration);
        ReentrantLock lock = new ReentrantLock();
        Condition waitCondition = lock.newCondition();

        while ((deadline-currentTime)>0) 
            try 
                lock.lockInterruptibly();    
                waitCondition.await(deadline-currentTime, TimeUnit.MILLISECONDS);
             catch (InterruptedException e) 
                Thread.currentThread().interrupt();
                return;
             finally 
                lock.unlock();
            
            currentTime = System.currentTimeMillis();
        
    

【讨论】:

【参考方案9】:

ScheduledThreadPoolExecutor有这个能力,但是相当重量级。

Timer也有这个能力,但即使只使用一次也会打开多个线程。

这是一个带有测试的简单实现(签名接近 android 的 Handler.postDelayed()):

public class JavaUtil 
    public static void postDelayed(final Runnable runnable, final long delayMillis) 
        final long requested = System.currentTimeMillis();
        new Thread(new Runnable() 
            @Override
            public void run() 
                // The while is just to ignore interruption.
                while (true) 
                    try 
                        long leftToSleep = requested + delayMillis - System.currentTimeMillis();
                        if (leftToSleep > 0) 
                            Thread.sleep(leftToSleep);
                        
                        break;
                     catch (InterruptedException ignored) 
                    
                
                runnable.run();
            
        ).start();
    

测试:

@Test
public void testRunsOnlyOnce() throws InterruptedException 
    long delay = 100;
    int num = 0;
    final AtomicInteger numAtomic = new AtomicInteger(num);
    JavaUtil.postDelayed(new Runnable() 
        @Override
        public void run() 
            numAtomic.incrementAndGet();
        
    , delay);
    Assert.assertEquals(num, numAtomic.get());
    Thread.sleep(delay + 10);
    Assert.assertEquals(num + 1, numAtomic.get());
    Thread.sleep(delay * 2);
    Assert.assertEquals(num + 1, numAtomic.get());

【讨论】:

它会在循环中发出警告睡眠 while 只是为了忽略干扰。【参考方案10】:
public static Timer t;

public synchronized void startPollingTimer() 
        if (t == null) 
            TimerTask task = new TimerTask() 
                @Override
                public void run() 
                   //Do your work
                
            ;

            t = new Timer();
            t.scheduleAtFixedRate(task, 0, 1000);
        
    

【讨论】:

虽然此代码可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。【参考方案11】:

也许最透明的方式是使用Handler类的postDelayed函数,方式如下:

new Handler().postDelayed(this::function, 1000);

或者你可以实现里面的功能,例如:

new Handler().postDelayed(() -> System.out.println("A second later"), 1000);

其中第一个参数是函数,第二个参数是延迟时间,以毫秒为单位。 在第一个例子中,被调用函数的名字是“function”。

【讨论】:

能否请您使用带有适当导入语句的示例程序更新答案,并提及哪个 java 版本可以成功运行。 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center。【参考方案12】:

我认为在这种情况下:

import javax.swing.*;
import java.awt.event.ActionListener;

是最好的。当问题是阻止 Ui 堆栈或在繁重的工作或网络调用之前不可见的进度时。我们可以使用以下方法(根据我的经验):

在一秒后运行一个方法:

 public static void startMethodAfterOneSeconds(Runnable runnable) 
        Timer timer = new Timer(1000, new ActionListener() 
            @Override
            public void actionPerformed(java.awt.event.ActionEvent e) 
                runnable.run();
            

        );
        timer.setRepeats(false); // Only execute once
        timer.start(); 
    

n 秒后运行一个方法一次,不重复:

public static void startMethodAfterNMilliseconds(Runnable runnable, int milliSeconds) 
    Timer timer = new Timer(milliSeconds, new ActionListener() 
        @Override
        public void actionPerformed(java.awt.event.ActionEvent e) 
            runnable.run();
        

    );
    timer.setRepeats(false); // Only execute once
    timer.start(); 

n秒后运行一个方法,然后重复:

 public static void repeatMethodAfterNMilliseconds(Runnable runnable, int milliSeconds) 
        Timer timer = new Timer(milliSeconds, new ActionListener() 
            @Override
            public void actionPerformed(java.awt.event.ActionEvent e) 
                runnable.run();
            

        );
        timer.setRepeats(true); // Only execute once
        timer.start(); 
    

以及用法:

 startMethodAfterNMilliseconds(new Runnable() 
            @Override
            public void run() 
                // myMethod(); // Your method goes here. 
            
        , 1000);

【讨论】:

以上是关于java:在特定秒数后运行函数的主要内容,如果未能解决你的问题,请参考以下文章

setTimeout()与setInterval()方法区别介绍

C语言alarm()函数(延时一段时间执行signal SIGALRM信号处理事件)

使用 YoutubeAPI 播放 youtube 视频直到特定时间并暂停

如何循环特定秒数

python延时函数

PHP:将秒数添加到日期