Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Runnable with a time limit

Trying to construct a Runnable that must end within a given time limit.

Currently I'm using java.util.Timer to interrupt Runnable thread.

Timer starts right after Runnable starts.

import java.util.Timer;
import java.util.TimerTask;

public class test {
    Thread task;
    Timer  timer;

    public void start(){

        task = new Thread(new worker());
        timer = new Timer("timer",true);

        task.start();
        timer.schedule(new Terminator(),1000*2);
    }


    class worker implements Runnable{
        @Override
        public void run() {

            for (int i = 0 ; i < 2; i++){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    System.out.println("Test Interrupted !!");
                    return;
                }
            }

            System.out.println("Test Finished !!");
            timer.cancel();
        }
    }

    class Terminator extends TimerTask{
        @Override
        public void run() {
            task.interrupt();
            System.out.println("Test Terminated !!");
        }
    }
}

But I suspect this results in a race condition between Timer and Runnable threads: Runnable is about to complete, and Timer is also firing.

Can this ever result in both Finished !! and Terminated !! being printed ? If so, how one avoids it ?

Update:

It happens:

11-09 21:14:40.741: INFO/System.out(31442): Test Finished !! 18
11-09 21:14:40.751: INFO/System.out(31442): Test Terminated !! 18
11-09 21:14:40.751: INFO/System.out(31442): Test Finished !! 19
11-09 21:14:40.751: INFO/System.out(31442): Test Terminated !! 19
like image 200
S.D. Avatar asked Feb 19 '23 13:02

S.D.


1 Answers

Can this ever result in both Finished !! and Terminated !! being printed ?

Yes. When the message "finished" is printed it's possible that the timer will fire before it is cancelled.

System.out.println("Finished !!");
// The timer can fire here.
timer.cancel(); 

If this happens, both messages will be printed.


To avoid the problem you can use synchronization.

synchronized (someObject) {
    if (!finished) {
        finished = true;
        System.out.println("Finished !!");
        timer.cancel(); 
    }
}

And in the terminator:

synchronized (someObject) {
    if (!finished) {
        finished = true;
        task.interrupt();
        System.out.println("Test Terminated !!");
    }
}

This prevents both messages form being printed.

like image 53
Mark Byers Avatar answered Feb 28 '23 08:02

Mark Byers