Sergey
Sergey

Reputation: 11918

Java create background thread which does something periodically

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?

Upvotes: 11

Views: 21837

Answers (5)

Sergii Stotskyi
Sergii Stotskyi

Reputation: 5390

There are lot of answers but nobody says why his example was not working. System.out is 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.

To make your example working you should add Thread.sleep into while loop in the main thread.

Upvotes: 2

Keppil
Keppil

Reputation: 46219

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

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

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

Upvotes: 1

Brian Agnew
Brian Agnew

Reputation: 272307

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

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

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

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;

Note also this interesting article on handling thread interruptions.

Upvotes: 3

assylias
assylias

Reputation: 328639

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

Now you could also use a ScheduledExecutorService, and use a Runnable instead of 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();

    }
}

Upvotes: 7

hmjd
hmjd

Reputation: 121971

Use java.util.TimerTask and java.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

Upvotes: 21

Related Questions