在Java中创建后台线程的最佳方式

7

如何创建一个后台线程,每15分钟从数据库获取数据?

下面是我已经拥有的代码,在生产环境中应该可以正常工作,但是否有更好的方式或者需要注意的事项呢?

private static void checkDatabaseEveryXMinutes() {
    new Thread() {
        public void run() {
            while (true) {
                try {
                    Thread.sleep(checkingAfterEveryXMinutes);
                    getDataFromDatabase();
                } catch (InterruptedException ex) {
                    //log here
                } catch (Exception e) {
                    //log here
                }
            }
        }
    }.start();
}

使用上述代码有什么缺点?ScheduledExecutorService和TimerTask有何区别?哪种方法更好?如果有更好的方法,请基于我的代码提供示例。


1
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html - SLaks
@SLaks感谢您的建议。我可以问一下,为什么您推荐这个而不是我上面提出的解决方案呢? - arsenal
@TechGeeky 很简单。使用你的方法,你必须编写自己的循环来睡眠和重新提交。使用 ScheduledExecutorService,你只需简单地 scheduleAtFixedRate(或 scheduleWithFixedDelay),一切都会自动处理好。 - C. K. Young
@ChrisJester-Young,感谢您的帮助。您能否基于我的代码提供一个简单的示例呢?因为没有人给出如何使用它的示例。所以任何关于此的帮助都将不胜感激。 - arsenal
3个回答

11

ScheduledExecutorService 会返回一个 Future,它具有另一种方法来检查 Runnable 是否已完成。两者都具有取消 Runnable 的方法。对于像这样的重复任务,检查其是否完成可能没有太大用处。然而,它是在 JDK 1.5 并发 API 中引入的,应该替代旧的并发/线程 API(Timer 和 TimerTask 是 JDK 1.3)。它们将更加健壮和更高效。在 Java 文档 此处 中有一个与您的使用情况非常相似的示例。

下面是一个示例:

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

public class ScheduledTaskExample {
    private final ScheduledExecutorService scheduler = Executors
        .newScheduledThreadPool(1);

    public void startScheduleTask() {
    /**
    * not using the taskHandle returned here, but it can be used to cancel
    * the task, or check if it's done (for recurring tasks, that's not
    * going to be very useful)
    */
    final ScheduledFuture<?> taskHandle = scheduler.scheduleAtFixedRate(
        new Runnable() {
            public void run() {
                try {
                    getDataFromDatabase();
                }catch(Exception ex) {
                    ex.printStackTrace(); //or loggger would be better
                }
            }
        }, 0, 15, TimeUnit.MINUTES);
    }

    private void getDataFromDatabase() {
        System.out.println("getting data...");
    }

    public void shutdowh() {
        System.out.println("shutdown...");
        if(scheduler != null) {
            scheduler.shutdown();
        }
    }

    public static void main(String[] args) {
        final ScheduledTaskExample ste = new ScheduledTaskExample();
        Runtime.getRuntime().addShutdownHook(new Thread() {
            public void run() {
                ste.shutdowh();
            }
        });
        ste.startScheduleTask();

    }
}

+1因为我同意你的答案,但是正如问题的提问者在评论中所说,你可能希望给他们举个例子,以免他们自己给自己惹麻烦。 :-) - C. K. Young
2
我想没有什么好争论的了,我猜是这样的.. 加了个例子 :) - Alper Akture
1
添加了一个重要的编辑!确保在关键代码周围放置try/catch,以防抛出异常。如果没有这个,异常将会终止线程并停止定时执行。 - Alper Akture
你能否编辑答案以添加一个语句来在应用程序关闭/失败时关闭线程?否则可能会造成内存泄漏的机会。 - anataliocs
@anatolics,添加了一个关闭功能。 - Alper Akture
显示剩余2条评论

2
您可以尝试使用java.util.TimerTaskjava.util.Timer
示例在这里:here-
Timer t = new Timer();

t.scheduleAtFixedRate(
    new TimerTask()
    {
        public void run()
        {
            System.out.println("3 seconds passed");
        }
    },
    0,      // run first occurrence immediately
    3000);

0

tieTYT说得对。如果您正在使用应用程序服务器,则可以使用特定服务器的ejbtimer服务。


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