Java create background thread which does something periodically
Asked Answered
H

5

11

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?

Hawes answered 17/7, 2012 at 10:41 Comment(5)
don't extend a thread (Its rarely necessary), rather implement a Runnable, see hereGomes
When you catch an exception, it is rarely a good thing to not do anything about it. At the very least, you need to print out what the exception is. Otherwise you won't even know if you caught an exception or not.Dispensatory
Agreed with Arnab Datta, rather use a ex.printStackTrace(); never leave catch blocks empty, its rather pointless thanGomes
how much cpu kernels do you have?Permutation
Actually the catch (InterruptedException e) handler should obviously contain a break; -- or just put while inside the try-block.Woosley
M
21

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
Moskow answered 17/7, 2012 at 10:44 Comment(5)
+1, and for the OP some code exampleGomes
@Sergey, yes it will. Each Timer object has a background thread. See the javadoc for more info.Moskow
@Hawes yes , The advantage of TimerTask is that it expresses your intention much better (i.e. code readability), and it already has the cancel() feature implemented.Gomes
..and ties up a threadpool thread for the duration of the timer call - if the timer callback itself makes blocking calls... Just saying - a timer task is not always the best solution.Florey
@Moskow and others : For scenario when we do not know how much timer task will take, I want to delay the execution by exact duration how can we do that ? For example : first execution of timer takes 5 seconds, second 3 seconds, third 8 seconds etc. But I want exact "sleep" time before each execution. So regardless of execution time, my delay should be same. How can I achieve that ?Abampere
I
7

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

    }
}
Ixtle answered 17/7, 2012 at 10:47 Comment(3)
This seems like the best answer - the I/O stream is blocked up with all those println() from the main thread. Using a timer or ScheduledExecutorService is fine, but does actually involve running extra threads and is difficult/awkward to implement when several layers down the stack in a complex thread with many function calls - it forces you into a state-machine that you may not want/need. Timers etc. are not always the best answer!Florey
@MartinJames It only involves running an additional thread which was what the OP was asking for. I am not sure I follow when you say "it forces you into a state-machine that you may not want/need".Ixtle
OK, example: your thread calls function A, which calls function B, which calls fuction C, where the code/data instructs that a 2 second wait is needed before continuing its operation and returning. For OP code, timer/Executor is fine - I only wished to say that a Timer/Executor is not for all cases where a wait is needed.Florey
F
3

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.

Felizio answered 17/7, 2012 at 10:43 Comment(0)
P
2

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.

Permutation answered 17/7, 2012 at 18:53 Comment(0)
S
1

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.

Sublingual answered 17/7, 2012 at 10:47 Comment(3)
It was not me, but I suspect that the downvoter feels that queueing such a task to a threadpool, (or using a timer, for that matter), may be overkill and cause excessive and avoidable context changes?Florey
@MartinJames: Could be. He/she apparently has something against using ScheduledExecutorService here, since @assylias's answer also got downvoted.Sublingual
Well, downvoter? I would only downvote an answer if it was actually totally wrong. If I think there's a better solution, or better explanation, I add a comment.Florey

© 2022 - 2024 — McMap. All rights reserved.