4

I'm trying to write a thread that monitors how long a blocking action takes. For example, I have a blocking action like this:

class BlockingThread extends Thread{

    public volatile boolean success = false;
    public volatile long startedTime = 0;

    public void run(){

      startedTime = System.currentTimeMillis();
      success = doBlockingAction(); //no idea how long this action will take
    }

}

and I want to have another Thread that will basically call a "timeout" function if the blocking action takes too long:

class MonitorThread extends Thread{

    public void run(){
      while(System.currentTimeMillis() - blockingThread.startedTime > TIMEOUT_DURATION)
      {
         ..keep waiting until the time runs out..
      }

      if(!blockingThread.success){
         listener.timeout();
         //Took too long.
      }
    }

}

I'm having trouble understanding how to ensure that the BlockingThread is actually currently on the blocking action while I'm measuring time in the MonitorThread.

If I do something like this,

Thread blockingThread = new BlockingThread();
blockingThread.start();
Thread monitorThread = new MonitorThread();
monitorThread.start();

there is no guarantee that one of the threads actually starts running the code before the other, and therefore I currently have no way of knowing if my timeout thread is actually measuring the time of the blocking action correctly. I assume the answer has to do with locking and waiting but I can't figure it out.

you786
  • 3,659
  • 5
  • 48
  • 74
  • I hope you mean `class BlockingThread` and `class MonitorThread`. – Jeffrey Aug 31 '12 at 00:57
  • There is a [question](http://stackoverflow.com/q/2275443/960195) on SO devoted to timing out method execution. That might be helpful here. – Adam Mihalcin Aug 31 '12 at 00:59
  • @Jeffrey Haha, oops. Thanks for the catch. – you786 Aug 31 '12 at 01:00
  • I don't understand why you can't simply do `while(blockingThread.startedTime == 0 || System.currentTimeMillis() - blockingThread.startedTime > TIMEOUT_DURATION)` – Adrian Shum Aug 31 '12 at 02:11
  • @AdrianShum Because the JVM can switch between threads at any moment. So the startedTime can be set to the current time, then before the very next line of the thread is executed (the blocking operation line), the JVM starts running a new thread. Or at least, that's how I understand it. – you786 Aug 31 '12 at 04:32
  • I believe unless you use instrumentation or similar techniques, this is the closest you can get. In a multi-threaded environment, it is almost impossible to get the real exact time that certain operation really starts to execute (as the reason you proposed). However normally the time slice is so small that you can reasonably ignore that. – Adrian Shum Aug 31 '12 at 06:26
  • @AdrianShum You're probably right. I'll leave the question open though to see if there are any better answers. – you786 Aug 31 '12 at 16:34

3 Answers3

4

I can advice you to rewrite your code using class java.util.concurrent.ThreadPoolExecutor. This class has nice method awaitTermination(), what, i suppose, is exactly you needed.

EDIT:

Here is your BlockingThread, running 10 second, and Monitor, waiting 5 seconds:

package sample.threadexecutor;

import java.text.SimpleDateFormat;
import java.util.Date;

public class BlockingThread implements Runnable{

    public boolean succsess = false;
    @Override
    public void run() {
        SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss.SSS");
        System.out.println(df.format(new Date())  + " start");
        try {
            Thread.sleep(10000L);
        } catch (InterruptedException e) {
            System.out.println(df.format(new Date())  + " interrupted");
            succsess = false;
            return;
        }
        System.out.println(df.format(new Date())  + " end");
        succsess = true;
    }
}

and main function with executor:

package sample.threadexecutor;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class main {

    public static void main(String[] args) {
        SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss.SSS");
        ExecutorService service= Executors.newSingleThreadExecutor();
        service.submit(new BlockingThread());
        try {
            service.shutdown();
            if(service.awaitTermination(5, TimeUnit.SECONDS)){
                System.out.println(df.format(new Date())  + " execution completed");
            }else{
                System.out.println(df.format(new Date())  + " execution timeout");
            }
        } catch (InterruptedException e) {
            System.out.println(df.format(new Date())  + " monitoring interrupted");
        }

    }
}

and output:

22:28:37.005 start
22:28:42.006 execution timeout
22:28:47.006 end

output if we set timeout to 20 seconds:

22:30:20.210 start
22:30:30.213 end
22:30:30.214 execution completed
user1516873
  • 5,060
  • 2
  • 37
  • 56
0

You might just have to loop around a few times before blockingThread.startingTime is initialized.

class MonitorThread extends Thread{

    public void run(){
        boolean weWantToKeepRunning = true;

        // here is your new event loop
        while(weWantToKeepRunning){

            if (blockingThread.startedTime != 0) && (System.currentTimeMillis() - blockingThread.startedTime > TIMEOUT_DURATION)&& (!blockingThread.success){

                listener.timeout();   // too long
                weWantToKeepRunning = false;  // quit this loop

            }
        }
    }
}
paulrehkugler
  • 3,241
  • 24
  • 45
0

what doBlockingAction does, exactly? Most blocking actions in Java API have variants which allow to set timeouts. Using that timed-out variants is the most accurate way.

Alexei Kaigorodov
  • 13,189
  • 1
  • 21
  • 38