Java每分钟循环一次

34

我想在Java中编写一个循环,它首先启动并按以下方式运行:

while (!x){
    //wait one minute or two

    //execute code
}

我希望做到这一点,而不会使用系统资源。 实际上,代码正在访问一个网站并检查某些内容是否完成,如果没有完成,则应等待另一分钟再次检查,当完成后,它就会继续执行。 有没有办法在Java中实现这个功能?

5个回答

71

你可以使用Timer

Timer timer = new Timer();

timer.schedule( new TimerTask() {
    public void run() {
       // do your work 
    }
 }, 0, 60*1000);

当时机到来时

  timer.cancel();

关闭它。


如果TimerTask需要运行55秒,那么它会在每次运行前等待5秒钟,还是像OP所问的那样等待一分钟? - polygenelubricants
6
它将像 OP 要求的那样等待一分钟。[Timer#scheduleAtFixedRate()] (http://java.sun.com/javase/6/docs/api/java/util/Timer.html#scheduleAtFixedRate%28java.util.TimerTask,%20long,%20long%29) 可以实现您所说的功能。 - BalusC
3
@BalusC:啊,有趣!schedule以固定延迟时间执行任务,而scheduleAtFixedRate则以固定间隔时间执行。很不错! - polygenelubricants
我尝试了这个方法并将我的代码放在run方法中,但是出现了一个关于从内部类访问局部变量的错误。 - Robert Cardona
@Robert:在这种情况下,尝试将那些变量声明为“final”。 - Platinum Azure
显示剩余2条评论

58

使用 Thread.sleep(long millis) 方法。

使当前线程暂停(暂时停止执行)指定的毫秒数,取决于系统计时器和调度程序的精度和准确性。线程不会失去任何监视器的所有权。

一分钟为 (60*1000) = 60000 毫秒。


例如,以下循环将每隔5秒钟打印一次当前时间:

    try {
        while (true) {
            System.out.println(new Date());
            Thread.sleep(5 * 1000);
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

如果你的睡眠时间超过了 int 的范围,就要明确地使用 long 进行计算(例如 1000L)。


我尝试了一下,但它没有起作用。我的代码如下: if (link.equalsIgnoreCase("exit") && count > 0) { boolean fetched = false; int myCounter = 0;try { while (!fetched) { System.out.println("Checking (" + myCounter + ")"); if (session.areLinkDoneFetching()) { session.getFetchData(); session.clearList(); fetched = true; } myCounter++; Thread.sleep(5 * 1000); } } catch (InterruptedException e) { e.printStackTrace(); } } - Robert Cardona
你说的“没用”是什么意思?它无法编译吗?它不能每次睡眠5秒钟吗? - polygenelubricants
它运行一次,然后就不做任何事情了。但程序仍在运行。 - Robert Cardona
我的代码出了点问题,不好意思,但是它自己运行得很正常。谢谢你的帮助,这正是我所需要的。 - Robert Cardona
就编程而言,我更喜欢使用下面的Timer类解决方案。 - Alan Thomas
Java 5及其后续版本内置的java.util.concurrent包是对此答案中所见代码的替代,也取代了Timer类。请参阅ScheduledExecutorService接口。 - Basil Bourque

15
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.schedule(yourRunnable, 1L, TimeUnit.MINUTES);
...
// when done...
executor.shutdown();

1
使用完毕后不要忘记shutdown(),否则线程会挂起。哦,原帖并没有要求按固定速率调度。只需使用schedule()即可。 - BalusC
请注意,如果线程处于循环中,则以下操作不会关闭线程。shutdownNow将中断线程(您需要处理)。 - user2130951
3
如果你只需要一个线程,可以使用Executors.newSingleThreadScheduledExecutor()代替Executors.newScheduledThreadPool(1); - Nicofisi

9

ScheduledExecutorService

Lee的回答很接近,但仅运行一次。问题似乎是要求在外部状态更改(直到来自网站/服务的响应更改)之前无限期运行。

ScheduledExecutorService接口是Java 5及其后续版本中内置的java.util.concurrent包的一部分,作为旧的Timer类的现代替代品。

以下是完整示例。调用scheduleAtFixedRatescheduleWithFixedDelay

ScheduledExecutorService executor = Executors.newScheduledThreadPool ( 1 );

Runnable r = new Runnable () {
    @Override
    public void run () {
        try {  // Always wrap your Runnable with a try-catch as any uncaught Exception causes the ScheduledExecutorService to silently terminate.
            System.out.println ( "Now: " + Instant.now () );  // Our task at hand in this example: Capturing the current moment in UTC.
            if ( Boolean.FALSE ) {  // Add your Boolean test here to see if the external task is fonud to be completed, as described in this Question.
                executor.shutdown ();  // 'shutdown' politely asks ScheduledExecutorService to terminate after previously submitted tasks are executed.
            }

        } catch ( Exception e ) {
            System.out.println ( "Oops, uncaught Exception surfaced at Runnable in ScheduledExecutorService." );
        }
    }
};

try {
    executor.scheduleAtFixedRate ( r , 0L , 5L , TimeUnit.SECONDS ); // ( runnable , initialDelay , period , TimeUnit )
    Thread.sleep ( TimeUnit.MINUTES.toMillis ( 1L ) ); // Let things run a minute to witness the background thread working.
} catch ( InterruptedException ex ) {
    Logger.getLogger ( App.class.getName () ).log ( Level.SEVERE , null , ex );
} finally {
    System.out.println ( "ScheduledExecutorService expiring. Politely asking ScheduledExecutorService to terminate after previously submitted tasks are executed." );
    executor.shutdown ();
}

期望的输出应该是这样的:
Now: 2016-12-27T02:52:14.951Z
Now: 2016-12-27T02:52:19.955Z
Now: 2016-12-27T02:52:24.951Z
Now: 2016-12-27T02:52:29.951Z
Now: 2016-12-27T02:52:34.953Z
Now: 2016-12-27T02:52:39.952Z
Now: 2016-12-27T02:52:44.951Z
Now: 2016-12-27T02:52:49.953Z
Now: 2016-12-27T02:52:54.953Z
Now: 2016-12-27T02:52:59.951Z
Now: 2016-12-27T02:53:04.952Z
Now: 2016-12-27T02:53:09.951Z
ScheduledExecutorService expiring. Politely asking ScheduledExecutorService to terminate after previously submitted tasks are executed.
Now: 2016-12-27T02:53:14.951Z

0
如果您正在使用SpringBoot应用程序,那么这非常简单。 ScheduledProcess
@Log
@Component
public class ScheduledProcess {

    @Scheduled(fixedRate = 5000)
    public void run() {
        log.info("this runs every 5 seconds..");
    }

}

Application.class

@SpringBootApplication
// ADD THIS ANNOTATION TO YOUR APPLICATION CLASS
@EnableScheduling
public class SchedulingTasksApplication {

    public static void main(String[] args) {
        SpringApplication.run(SchedulingTasksApplication.class);
    }
}

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