Java 创建后台线程,定期执行某些操作

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11520819/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 05:24:45  来源:igfitidea点击:

Java create background thread which does something periodically

javamultithreading

提问by Sergey

Is it possible to create a separate background thread which would separately do some stuff? I've tried the following program but it doesn't work as I expect.

是否可以创建一个单独的后台线程来单独做一些事情?我已经尝试了以下程序,但它没有按我预期的那样工作。

public class Test {

    private static class UpdaterThread extends Thread {
        private final int TIMEOUT = 3000;

        public void run() {
            while (true) {
                try {
                    Thread.sleep(TIMEOUT);
                    System.out.println("3 seconds passed");
                } catch (InterruptedException ex) {
                }
            }
        }
    }

    /**
     * @param args
     *            the command line arguments
     */
    public static void main(String[] args) {
        try {
            Thread u = new UpdaterThread();
            u.start();
            while (true) {
                System.out.println("--");
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

I expected that every 3 seconds "3 seconds passed" will be printed in the flow of multiple "--" strings. In fact "3 seconds passed" is never printed. Why? And how can I create a background thread which would do something independantly from the main thread?

我预计每 3 秒“3 秒过去”将打印在多个“--”字符串的流中。事实上,“3 秒过去了”永远不会被打印出来。为什么?以及如何创建一个后台线程来独立于主线程执行某些操作?

回答by hmjd

Use java.util.TimerTaskand java.util.Timer:

使用java.util.TimerTaskjava.util.Timer

Timer t = new Timer();

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

回答by assylias

It does print "3 seconds passed". Remove the System.out.println("--")and you will see them more easily ;-)

它确实打印“3 秒过去了”。删除它们System.out.println("--"),您将更容易看到它们;-)

Now you could also use a ScheduledExecutorService, and use a Runnableinstead of a Thread:

现在您还可以使用 a ScheduledExecutorService,并使用 aRunnable代替 a Thread

public class Test {

    private static class Updater implements Runnable {

        @Override
        public void run() {
            System.out.println("3 seconds passed");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Runnable r = new Updater();
        ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
        service.scheduleAtFixedRate(r, 0, 3, TimeUnit.SECONDS);

        Thread.sleep(10000);
        service.shutdown();

    }
}

回答by Brian Agnew

You can use the above approach to run stuff periodically, although a TimerTaskmay be simpler.

您可以使用上述方法定期运行东西,尽管 aTimerTask可能更简单。

With respect to your output, I suspect your main thread isn't allowing your UpdaterThreadto run, since it's in a very tight loop. Note that this would be dependent on CPUs/cores available etc.

关于您的输出,我怀疑您的主线程不允许您UpdaterThread运行,因为它处于一个非常紧密的循环中。请注意,这将取决于可用的 CPU/内核等。

Have you considered sleeping in your mainthread, or using Thread.yield()? Note the provisos in that linked page:

您是否考虑过在线程中休眠或使用Thread.yield()?请注意该链接页面中的附带条件:

When to use yield()?

I would say practically never. Its behaviour isn't standardly defined and there are generally better ways to perform the tasks that you might want to perform with yield(): if you're trying to use only a portion of the CPU, you can do this in a more controllable way by estimating how much CPU the thread has used in its last chunk of processing, then sleeping for some amount of time to compensate: see the sleep() method;

什么时候使用yield()?

我会说几乎永远不会。它的行为没有标准定义,并且通常有更好的方法来执行您可能希望使用 yield() 执行的任务:如果您尝试仅使用 CPU 的一部分,则可以以更可控的方式执行此操作通过估计线程在其最后一个处理块中使用了多少 CPU,然后休眠一段时间来进行补偿:参见 sleep() 方法;

Note also this interesting articleon handling thread interruptions.

还要注意这篇关于处理线程中断的有趣文章

回答by Keppil

I would recommend using a ScheduledExecutorService. To run your UpdaterThread()every 3 seconds, you can do like this:

我建议使用ScheduledExecutorService. 要UpdaterThread()每 3 秒运行一次,您可以这样做:

ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new UpdaterThread(), 0, 3000, TimeUnit.MILLISECONDS);

You can read more here: Java Tutorials - Executor Interfaces.

您可以在此处阅读更多信息:Java 教程 - 执行程序接口

回答by Sergii Stotskyi

There are lot of answers but nobody says why his example was not working. System.outis output stream, so after you have started write to this stream JAVA locks it and all other threads will wait while lock is applied to stream. After the stream will have unlocked another thread will be able to work with this stream.

有很多答案,但没有人说为什么他的例子不起作用。System.out是输出流,因此在您开始写入此流后,JAVA 会锁定它,而所有其他线程将在将锁定应用于流时等待。在流解锁后,另一个线程将能够使用该流。

To make your example working you should add Thread.sleepinto whileloop in the main thread.

为了使您的示例工作,您应该在主线程中添加Thread.sleepwhile循环中。