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?

Pshemo
  • 122,468
  • 25
  • 185
  • 269
Sergey
  • 11,548
  • 24
  • 76
  • 113
  • don't extend a thread (Its rarely necessary), rather implement a `Runnable`, see [here](http://stackoverflow.com/questions/541487/java-implements-runnable-vs-extends-thread) – David Kroukamp Jul 17 '12 at 10:44
  • 1
    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. – Arnab Datta Jul 17 '12 at 10:45
  • Agreed with Arnab Datta, rather use a `ex.printStackTrace();` never leave catch blocks empty, its rather pointless than – David Kroukamp Jul 17 '12 at 10:46
  • how much cpu kernels do you have? – Sergii Stotskyi Jul 17 '12 at 10:49
  • Actually the `catch (InterruptedException e)` handler should obviously contain a `break;` -- or just put `while` **inside** the try-block. – Marko Topolnik Jul 17 '12 at 10:53

5 Answers5

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
hmjd
  • 120,187
  • 20
  • 207
  • 252
  • +1, and for the OP some code [example](http://enos.itcollege.ee/~jpoial/docs/tutorial/essential/threads/timer.html) – David Kroukamp Jul 17 '12 at 10:45
  • @Sergey, yes it will. Each `Timer` object has a background thread. See the javadoc for more info. – hmjd Jul 17 '12 at 10:49
  • @Sergey 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. – David Kroukamp Jul 17 '12 at 10:50
  • ..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. – Martin James Jul 17 '12 at 11:05
  • @hmjd 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 ? – java_enthu Mar 18 '14 at 14:28
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();

    }
}
David Kroukamp
  • 36,155
  • 13
  • 81
  • 138
assylias
  • 321,522
  • 82
  • 660
  • 783
  • 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! – Martin James Jul 17 '12 at 10:58
  • @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"*. – assylias Jul 17 '12 at 11:01
  • 1
    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. – Martin James Jul 17 '12 at 11:20
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.

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
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.

Sergii Stotskyi
  • 5,134
  • 1
  • 22
  • 21
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.

Keppil
  • 45,603
  • 8
  • 97
  • 119
  • 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? – Martin James Jul 17 '12 at 11:01
  • @MartinJames: Could be. He/she apparently has something against using `ScheduledExecutorService` here, since @assylias's answer also got downvoted. – Keppil Jul 17 '12 at 11:03
  • 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. – Martin James Jul 17 '12 at 11:07