I need to execute a Java method for at most X seconds.
In case the method's code does not terminate after X seconds, I need my execution to continue.
I tried to use the following code (using the ExecutorService class).
private void execLoop(){
ExecutorService executor = Executors.newSingleThreadExecutor();
int iteration;
for(iteration=0;iteration<10;iteration++) {
CallableTask ct = new CallableTask();
Future<String> future = executor.submit(ct);
try {
future.get(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
class CallableTask implements Callable {
#Override
public Object call() throws Exception {
Log.d("TIME","executed!");
int t=0;
boolean c = true;
while(c){
t+=0; // infinite loop: this method will never terminate
}
return null;
}
}
What I expect from this code is to print to logcat, every 5 seconds, the string "executed!" for 10 times.
However, the execution gets stuck in the infinite loop.
First, you never shut down your executor. Add the following line as the last statement in your execLoop() method:
executor.shutdownNow();
Then, since the shutdown is accomplished by interrupting your threads, you need to make sure that your CallableTask listens to interrupts. One way is to use Thread.sleep() instead of t+=0:
while(c){
Thread.sleep(500); // This will be interrupted when you call shutdownNow()
}
Related
I want to run a thread for some fixed amount of time.
If it is not completed within that time, I want to either kill it, throw some exception, or handle it in some way. How can this be done?
You should use an ExecutorService:
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(new Task());
try {
System.out.println("Started");
Integer retval = future.get(10, TimeUnit.SECONDS)); // you can choose your desired time here
System.out.println("Finished");
} catch (TimeoutException e) {
future.cancel(true);
System.out.println("Timeout happened");
// handle termination here
}
executor.shutdownNow();
And your Callable can look something like this:
class Task implements Callable<Integer> {
#Override
public String call() throws Exception {
// some code here
return 0;
}
}
I have a method, which writes to the database. The requirement is to make sure that this method does not execute after a certain time elapses. If it returns before that, then nothing should be done.
The one basic approach that I can think of is doing something like this.
public class LimitedRuntime {
public static void writeToDb(){
// writes to the database
}
public static void main(String[] args) {
long totalExecutionTime = 8000L;
long startTime = System.currentTimeMillis();
while(System.currentTimeMillis() - startTime < totalExecutionTime )
{
writeToDb();
}
}
}
One problem with this approach is that even if the method returns before the max total execution time, even then the program halts so as to wait for the time to elapse.
How can I do this better (or maybe more correctly) ? And if we use Thread, how can we find out which Thread executes that method ?
You can do this by sending your job to an executor:
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(4);
Future<?> future = executor.submit(new Runnable() {
#Override
public void run() {
writeToDb(); // <-- your job
}
});
executor.shutdown(); // <-- reject all further submissions
try {
future.get(8, TimeUnit.SECONDS); // <-- wait 8 seconds to finish
} catch (InterruptedException e) { // <-- possible error cases
System.out.println("job was interrupted");
} catch (ExecutionException e) {
System.out.println("caught exception: " + e.getCause());
} catch (TimeoutException e) {
future.cancel(true); // <-- interrupt the job
System.out.println("timeout");
}
// wait all unfinished tasks for 2 sec
if(!executor.awaitTermination(2, TimeUnit.SECONDS)){
// force them to quit by interrupting
executor.shutdownNow();
}
}
There is also an AspectJ solution for that with jcabi-aspects library:
#Timeable(limit = 5, unit = TimeUnit.SECONDS)
public String writeToDb() {
// writeToDb
}
There is an article explaining it further: Limit Java Method Execution Time
I have implmented a TimeoutTask using ExecutorService. In the below method I am submitting the TimeoutTask and if it is timed out in a given time, I cancel the task and shuts down the executor.
private boolean waitForProcessToBeCompleted(long timeOut) {
boolean result = false;
ExecutorService executor = Executors.newSingleThreadExecutor();
// Create a FutureTask which will be run
FutureTask<Boolean> futureTask = new FutureTask<Boolean>(new TimeoutTask());
executor.submit(futureTask); // Run the FutureTask
try {
result = futureTask.get(timeOut, TimeUnit.MILLISECONDS); // Check if FutureTask completed in the given time
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
futureTask.cancel(true);
result = true; // Return True only when timed out
} finally {
executor.shutdownNow(); // Stop the executor
}
return result;
}
It is running very well and I don't have any issue.
However, I would like to know whether this is the best code design. I was just wondering if it could have been better to use a Future returned by ExecutorService.submit() to get the return value of the Callable or to time out the TimeoutTask. e.g.
Future<?> futureTask = executor.submit(new TimeoutTask()); // Run the FutureTask
try {
result = futureTask.get(timeOut, TimeUnit.MILLISECONDS); // Check if FutureTask completed in the given time
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
futureTask.cancel(true);
result = true; // Return True only when timed out
} finally {
executor.shutdownNow(); // Stop the executor
}
return result;
I am using JDK7.
I would prefer using CountDownLatch:
List<List<String>> elements = MyPartition.partition(bigObjectList, size);
List<Future<?>> tasks = new ArrayList<Future<?>>();
ExecutorService executor = Executors.newSingleThreadExecutor();
CountDownLatch doneSignal = new CountDownLatch(10);
for(List<String> l: elements) {
ReadTask worker = new ReadTask(doneSignal, l);
tasks.add(executor.submit(worker));
}
long timeout = 10000;
doneSignal.await(timeout, TimeUnit.SECONDS);
boolean notFinished = false;
if(doneSignal.getCount() > 0) {
for(Future<?> fut : tasks) {
if(!fut.isDone()) {
System.out.println("Sub Thread " + fut + " has not finshed!");
fut.cancel(true);
notFinished = true;
}
}
}
If you look at the code of futureTask.cancel, you'll see that it just attempts to interrupt the thread which is executing the task. This interruption may work if the task regullary checks the interruption flag, explicitly or implicitly (via calling to sleep() or wait()). In Java, there is no other safe way to stop execution of a method.
So, you can implement the same functionality without creating each time a separate single-threaded executor. Instead, execute the TimerTask from within the waitForProcessToBeCompleted method. In order to be notified of timeout, submit a watching task to a SheduledExecutorService. The watching task should interrupt the thread which executes the TimerTask. If the task is completed before timeout, cancel the watching task.
This way you need a SheduledExecutorService, but it consumes very little processor cycles, and can be reused all over the application.
The invokeAll method on ExecutorService can be used to automatically cancel tasks that exceed the timeout. This lets you cancel tasks without shutting down the threadpool (which let's you re-use the same threadpool for other things if you choose).
private boolean waitForProcessToBeCompleted(long timeOut) {
ExecutorService executor = Executors.newSingleThreadExecutor();
List<FutureTask> tasks = new ArrayList<>();
tasks.add(new SomeFutureTaskThing()));
List<Future<Boolean>> results;
try {
results = executor.invokeAll(tasks, timeOut, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // Restore interrupt status.
return null;
} catch (ExecutionException e) {
throw new RuntimeException(e.getCause());
}
Future<Boolean> result = results.get(0);
try {
return result.get();
} catch (CancellationException e) {
System.err.println("Timed out");
return null;
}
}
I'm using this code to divide up a few hundred tasks between different CPU cores.
final List<Throwable> errors = Collections.synchronizedList(Lists.<Throwable>newArrayList());
final ExecutorService pool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
for (...) {
pool.execute(new Runnable() { #Override public void run() {
try {
// TASK HERE
} catch (Throwable e) {
errors.add(e);
}
}});
}
pool.shutdown();
try {
pool.awaitTermination(1000, TimeUnit.DAYS); // wait "indefinitely"
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (!errors.isEmpty()) throw Exceptions.wrap(errors.get(0)); // TODO multi-exception
It works, but it's not nice.
There is no version of awaitTermination without timeout, which is what I want.
I need to do my own error collecting.
What is the proper/common way to do this?
The point of a thread pool is to reuse threads. You should create it on application startup, outside of your code that creates tasks, and inject it. There is no need to shut down the pool after adding tasks. You do that when your application is shutting down.
To run a collection of tasks, use ExecutorService.invokeAll. To get the results afterwards, call get on each of the returned Futures. It will rethrow any exception that the task threw, so you can collect it afterwards.
You can use a future to do the error handling:
final List<Future> futures = new ArrayList<Future>();
for (int i = 0; i < 5; i++) {
futures.add(pool.submit(new Runnable() { #Override public void run() {
// TASK HERE
}}));
}
for (Future f : futures) {
try {
f.get();
} catch (ExecutionException e) {
//something bad happened in your runnable
}
}
//when you are done with the executor
pool.shutdown();
try {
pool.awaitTermination(1000, TimeUnit.DAYS); // wait "indefinitely"
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
I think you need to submit each Runnable, get a Future back, and then call get() on each Future.
When you call get(), you'll either get the result of the Runnable, or the exception that it encountered.
Below is a sample program. If i uncomment the Thread.sleep it works fine.
But there may be some need, where we are not sure how much time the code written inside Call method takes, can be a infinite time. Or, can be a bad program where the DB connection logic inside Call method takes more time and we need to kill.
Could you please tell, why the below code does not work if i comment the thread.sleep and how to kill and stop that without writing Thread.interrupted condition. (Assume i do not have permission write any logic inside the Call method)
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class stopThreadTest {
public static void main(String[] args) {
java.util.concurrent.ExecutorService executor = null;
Future a1 = null;
try {
executor = java.util.concurrent.Executors.newFixedThreadPool(4);
a1 = executor.submit(new java.util.concurrent.Callable() {
public String call() throws Exception {
int i = 0;
while (true) {
//Thread.sleep(100);
// System.out.println("hello");
if (i > 10)
break;
}
return null;
}
});
// Wait until all threads are finish
/*
* while (!executor.isTerminated()) { }
*/
System.out.println("Calling PartialOrFullSuccessCheck");
try {
boolean isThreadError = (a1 != null) ? ((a1.get(2,
TimeUnit.SECONDS) == null) ? false : true) : false;
} catch (TimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
// interrupts the worker thread if necessary
System.out
.println("Cancelled" + a1.isDone() + a1.isCancelled());
a1.cancel(true);
System.out.println("encountered problem while doing some work");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
// interrupts the worker thread if necessary
System.out
.println("Cancelled" + a1.isDone() + a1.isCancelled());
a1.cancel(true);
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
// interrupts the worker thread if necessary
System.out
.println("Cancelled" + a1.isDone() + a1.isCancelled());
a1.cancel(true);
}
} finally {
System.out.println("ShutDown Executor");
executor.shutdown();
}
}
}
There is no safe way to stop a thread without its cooperation. Threads allow other threads to stop them by being interrupted, by periodically checking the value of some shared variable or both. Other than that, the only safe thing to do is shut down the JVM (the whole process). This post is quite detailed:
How do you kill a thread in Java?