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


148

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

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

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


您是否要等待5秒然后执行某项操作,还是要在5秒内继续执行其他操作?
whiskeysierra

我想继续做点别的
ufk

Answers:


228
new java.util.Timer().schedule( 
        new java.util.TimerTask() {
            @Override
            public void run() {
                // your code here
            }
        }, 
        5000 
);

编辑:

javadoc说:

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


1
如果运行该代码,则会泄漏线程。完成后,请确保清理计时器。
skaffman'2

1
@skaffman:我在javadoc中添加了一条语句。打电话时间表后,您真的需要打扫吗?
坦根

1
可能还可以,但随后可能不行。如果您多次运行该代码片段,则将有松散的线程在踢,而没有整理它们的方法。
skaffman'2

5
import java.util.Timer; import java.util.TimerTask;可能更明显的是不是javax.swing.Timer。/注意,如果您使用的是Swing(实际上是AWT),则不应做任何事情来更改非事件调度线程(EDT)线程上的组​​件(java.util.Timer任务不好;javax.swing.Timer动作很好)。
Tom Hawtin-大头钉

2
@PaulAlexander根据文档- cancel在run方法结束时调用timer 方法将清除TimerTasks的执行线程。
丹达夫

58

像这样:

// 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()将立即终止线程池。


24

使用范例 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提到的,您应该查找“ 如何使用Swing计时器 ”以作简短介绍。


6

我的代码如下:

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

5

作为@tangens的一个变体:如果您迫不及待想要垃圾回收器清理线程,请在run方法结束时取消计时器。

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它吗?
约书亚·品特

1
@JoshuaPinter是的,应该声明为final,但它并不需要显式声明为final至少在Java的8它只需要“有效终”(javarevisited.blogspot.com/2015/03/...
Dandalf

4

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

阅读Swing教程中“ 如何使用计时器 ”部分,以获取更多信息。


4

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

Thread.sleep(4000);
myfunction();

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


而且它仅保证执行将在4秒后运行,这也可能意味着在10秒后运行!
Questzen 2010年

2
疑问,您会发现这里的所有方法都可以做到这一点。实际上,即使您要在操作系统级别安排某些活动,通常也只能保证在事件发生之前经过最少的时间。
伊桑(Ethan)

这不是真正的问题是什么
Inder R Singh

我只得对此打个招呼-根本不回答眼前的问题。
theMayer

OP在评论中说:“我想继续做其他事情”;这段代码显然没有。
Abhijit Sarkar,

3

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

它给出了循环中警告睡眠的提示
shareef

while只是忽略中断。
AlikElzin-kilaka

2

其他所有需要解决的问题都需要在新线程中运行您的代码。在一些简单的用例中,您可能只需要稍等片刻并在同一线程/流中继续执行。

下面的代码演示了该技术。请记住,这类似于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();
        }
    }
}

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

2
尽管此代码可以回答问题,但提供有关此代码为什么和/或如何回答问题的其他上下文,可以改善其长期价值。
Mateus
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.