Executor Service does not timeout and continues to run - java

I have the following code:
def getIndustryData(String[] theIndustries) {
PrintWriter printWriter = new PrintWriter(new BufferedWriter(new FileWriter("result.txt")))
//Listens to Twitter statuses and carries out the following methods on the status
StatusListener listener = new StatusListener() {
#Override
void onStatus(Status status) {
printWriter.write(status.getLang() + "|||" + status.getText())
printWriter.println()
}
#Override
void onDeletionNotice(StatusDeletionNotice statusDeletionNotice) {
}
#Override
void onTrackLimitationNotice(int numberOfLimitedStatuses) {
}
#Override
void onScrubGeo(long userId, long upToStatusId) {
}
#Override
void onStallWarning(StallWarning warning) {
}
#Override
void onException(Exception ex) {
}
}
TwitterStream stream = new TwitterStreamFactory().getInstance()
stream.addListener(listener)
FilterQuery fq = new FilterQuery()
fq.track(theIndustries)
ExecutorService executor = Executors.newSingleThreadExecutor()
Future<String> future = executor.submit(new Callable<String>() {
#Override
String call() throws Exception {
stream.filter(fq)
return null
}
})
try {
future.get(2, TimeUnit.MINUTES)
} catch (TimeoutException e) {
stream.removeListener(listener)
stream.shutdown()
future.cancel(true)
executor.shutdownNow()
}
}
I am using Twitter4J to access the Twitter API.I want to write tweets to a file for 2 minutes and then stop.
The stream.filter(fq) method runs even after the stated 2 minutes and the TimeoutException is never reached. I thought after the 2 minutes the exception would be caught and I could end the method however this does not happen.

You have wrong mental model of how TwitterStream works and also most probably of how standard java Future and ExecutorService work.
TwitterStream doesn't work on any Thread you provide to it. TwitterStream .filter starts new thread internally as you can see at the source at https://github.com/yusuke/twitter4j/blob/master/twitter4j-stream/src/main/java/twitter4j/TwitterStreamImpl.java#L317 and https://github.com/yusuke/twitter4j/blob/master/twitter4j-stream/src/main/java/twitter4j/TwitterStreamImpl.java#L516
Also Future.get with timeout method is not guaranteed to fail with TimeoutException. If the job is fast, it just returns value. And this is exactly your case! stream.filter(fq) creates new Thread which is fast and then your future immediately returns null.
The simplest (but probably not the best) way to make it work is something like this
stream.filter(fq)
try
{
Thread.sleep(2 * 60 * 1000); // just sleep on the caller thread
}
catch (InterruptedException e)
{
// ignore
}
stream.removeListener(listener)
stream.cleanup()
//stream.shutdown() //don't think you really need shutdown, cleanup seems to be enough

Related

Detecting a timeout exception on a Java Future without calling get() on it

I am building a library that needs to some bluetooth operations on Android. I want to return a Future instance, so whoever is using my library can call .get() on the future returned and can handle ExecutionException, TimeoutException and InterruptedException themselves. However, I want to detect a timeout myself because I need to some cleanup logic like disconnecting from the device and so on. How can I achieve this?
You could implement a wrapper class around Future which delegates to a different one (the one returned by wherever you're getting your Future at the moment). Something like:
final class DelegatingFuture<T> implements Future<T> {
private final Future<T> delegate;
DelegatingFuture(final Future<T> delegate) {
this.delegate = Objects.requireNonNull(delegate);
}
// All other methods simply delegate to 'delegate'
#Override
public T get()
throws InterruptedException, ExecutionException {
try {
return this.delegate.get();
} catch (final Exception ex) {
// Handle cleanup...
throw ex;
}
}
// Something similar for get(long timeout, TimeUnit unit)
}
And then simply return new DelegatingFuture<>(currentFuture); wherever your handing these out.
The timeout is relevant to the caller of the get method with timeout and only to that caller. A timeout is nowhere meant to imply a cancellation. E.g., the following code is a legitimate usage of the Future API:
ExecutorService es = Executors.newSingleThreadExecutor();
Future<String> f = es.submit(() -> {
Thread.sleep(3000);
return "hello";
});
for(;;) try {
String s = f.get(500, TimeUnit.MILLISECONDS);
System.out.println("got "+s);
break;
}
catch(TimeoutException ex) {
// perhaps, do some other work
System.out.println("will wait something more");
}
catch (ExecutionException ex) {
System.out.println("failed with "+ex);
break;
}
es.shutdown();
Tying the cleanup to the methods actually intended to query the result, is not a useful approach. The timeout provided by the caller(s) of that method do not relate to the actual operation. There’s not even a guaranty that the result will be queried before the operations ends or that it gets queried at all.
The cleanup should happen when either, the operation finished or when the future gets cancelled explicitly. If the caller intends a cancellation after a timeout, the caller only needs to invoke cancel after catching a TimeoutException.
One approach, often pointed to, is to use a CompletionService, e.g.
static final ExecutorService MY__EXECUTOR = Executors.newCachedThreadPool();
static final CompletionService<String> COMPLETION_SERVICE
= new ExecutorCompletionService<>(MY__EXECUTOR);
static final Future<?> CLEANER = MY__EXECUTOR.submit(() -> {
for(;;) try {
Future<String> completed = COMPLETION_SERVICE.take();
System.out.println("cleanup "+completed);
} catch(InterruptedException ex) {
if(MY__EXECUTOR.isShutdown()) break;
}
});
public static Future<String> doSomeWork() {
return COMPLETION_SERVICE.submit(() -> {
Thread.sleep(3000);
return "hello";
});
}
You are in control over when to poll the completed futures, like in another background thread, as shown in the example, or right before commencing new jobs.
You can test it like
Future<String> f = doSomeWork();
try {
String s = f.get(500, TimeUnit.MILLISECONDS);
System.out.println("got "+s);
}
catch(TimeoutException ex) {
System.out.println("no result after 500ms");
}
catch (ExecutionException ex) {
System.out.println("failed with "+ex);
}
if(f.cancel(true)) System.out.println("canceled");
f = doSomeWork();
// never calling get() at all
But honestly, I never understood why such complicated things are actually necessary. If you want a cleanup at the right time, you can use
static final ExecutorService MY__EXECUTOR = Executors.newCachedThreadPool();
public static Future<String> doSomeWork() {
Callable<String> actualJob = () -> {
Thread.sleep(3000);
return "hello";
};
FutureTask<String> ft = new FutureTask<>(actualJob) {
#Override
protected void done() {
System.out.println("cleanup "+this);
}
};
MY__EXECUTOR.execute(ft);
return ft;
}
to achieve the same.
Or even simpler
static final ExecutorService MY__EXECUTOR = Executors.newCachedThreadPool();
public static Future<String> doSomeWork() {
Callable<String> actualJob = () -> {
Thread.sleep(3000);
return "hello";
};
return MY__EXECUTOR.submit(() -> {
try {
return actualJob.call();
}
finally {
// perform cleanup
System.out.println("cleanup");
}
});
}
In either case, the cleanup will be performed whether the job was completed successfully, failed, or got canceled. If cancel(true) was used and the actual job supports interruption, the cleanup also will be performed immediately after.

Standard Java pattern for wrapping a timeout around an errant process

I'm using a 3rd party function (say runThird()) that has a tendency to loop indefinitely and has no timeout facility built in. However, I can kill it (killThird()). Is there a proper way to do this (i.e. some concurrency construct)?
Here's my attempt at this:
java.lang.Thread thread = new Thread(new Runnable(){
#Override
public void run(){
try {
Thread.sleep(TIMEOUT);
} catch (java.lang.InterruptedException e){
return;
}
killThird();
}
});
thread.start();
RunThirdResult rtr = runThird();
if (thread != null){
thread.interrupt();
}
But I'm not sure I like the overhead of creating a thread, using sleep and the contrivance of interrupting the thread if runThird() returns.
Let's assume runThird() retuns Integer ...
// ... in your class ...
private ExecutorService executor = Executors.newCachedThreadPool();
//... then somewhere, where you want to call runThird()
Future<Integer> handle = executor.submit( new Callable<Integer>(){
#Override Integer call(){
return runThird(); // Assume you made it available here ...
}
}
Integer result;
try{
result = handle.get(TIMEOUT,UNIT); // TIMEOUT and UNIT declared somewhere above ...
}
catch(TimeoutException ex) {
killThird();
// HANDLE result not being set!
}
// ... use result.
I would use a ScheduledExecutorService for this. Schedule it to be killed.
volatile RunThirdResult rtr;
ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
service.schedule(new Runnable(){
public void run(){
if(rtr == null) killThird();
}
}, TIMEOUT_IN_MILLIS, TimeUnit.MILLISECONDS);
RunThirdResult rtr = runThird();
Something like that? The most interesting part is StoppableWrapper#stop(), cause graceful cancellation is a hard thing and there's no common approach for all cases. One time you need to clear filesystem, other time to close network connection, etc. In your sample, you just call interrupt(), so I assumed runThird() honors being interrupted and will take care to clean things behind itself.
class Sample {
final ExecutorService tasksExecutor = Executors.newCachedThreadPool();
class StoppableWrapper implements Runnable {
private final Runnable task;
private final CountDownLatch executed;
StoppableWrapper(Runnable task, CountDownLatch executed) {
this.task = task;
this.executed = executed;
}
void stop() {
// e.g. Thread.currentThread().interrupt()
}
#Override
public void run() {
task.run();
executed.countDown();
}
}
public void scheduleTimingOutTaskExecution(final long timeout) {
final CountDownLatch executed = new CountDownLatch(1);
final StoppableWrapper command = new StoppableWrapper(new RunThirdInstance(), executed);
tasksExecutor.execute(command);
tasksExecutor.execute(new Runnable() {
#Override
public void run() {
try {
if (!executed.await(timeout, TimeUnit.MILLISECONDS)) {
command.stop();
// additionally, you can make stop() return boolean after time-out as well and handle failure
}
} catch (InterruptedException e) {
// handle stopper exception here
}
}
});
}
}

Java: set timeout on a certain block of code?

Is it possible to force Java to throw an Exception after some block of code runs longer than acceptable?
Here's the simplest way that I know of to do this:
final Runnable stuffToDo = new Thread() {
#Override
public void run() {
/* Do stuff here. */
}
};
final ExecutorService executor = Executors.newSingleThreadExecutor();
final Future future = executor.submit(stuffToDo);
executor.shutdown(); // This does not cancel the already-scheduled task.
try {
future.get(5, TimeUnit.MINUTES);
}
catch (InterruptedException ie) {
/* Handle the interruption. Or ignore it. */
}
catch (ExecutionException ee) {
/* Handle the error. Or ignore it. */
}
catch (TimeoutException te) {
/* Handle the timeout. Or ignore it. */
}
if (!executor.isTerminated())
executor.shutdownNow(); // If you want to stop the code that hasn't finished.
Alternatively, you can create a TimeLimitedCodeBlock class to wrap this functionality, and then you can use it wherever you need it as follows:
new TimeLimitedCodeBlock(5, TimeUnit.MINUTES) { #Override public void codeBlock() {
// Do stuff here.
}}.run();
I compiled some of the other answers into a single utility method:
public class TimeLimitedCodeBlock {
public static void runWithTimeout(final Runnable runnable, long timeout, TimeUnit timeUnit) throws Exception {
runWithTimeout(new Callable<Object>() {
#Override
public Object call() throws Exception {
runnable.run();
return null;
}
}, timeout, timeUnit);
}
public static <T> T runWithTimeout(Callable<T> callable, long timeout, TimeUnit timeUnit) throws Exception {
final ExecutorService executor = Executors.newSingleThreadExecutor();
final Future<T> future = executor.submit(callable);
executor.shutdown(); // This does not cancel the already-scheduled task.
try {
return future.get(timeout, timeUnit);
}
catch (TimeoutException e) {
//remove this if you do not want to cancel the job in progress
//or set the argument to 'false' if you do not want to interrupt the thread
future.cancel(true);
throw e;
}
catch (ExecutionException e) {
//unwrap the root cause
Throwable t = e.getCause();
if (t instanceof Error) {
throw (Error) t;
} else if (t instanceof Exception) {
throw (Exception) t;
} else {
throw new IllegalStateException(t);
}
}
}
}
Sample code making use of this utility method:
public static void main(String[] args) throws Exception {
final long startTime = System.currentTimeMillis();
log(startTime, "calling runWithTimeout!");
try {
TimeLimitedCodeBlock.runWithTimeout(new Runnable() {
#Override
public void run() {
try {
log(startTime, "starting sleep!");
Thread.sleep(10000);
log(startTime, "woke up!");
}
catch (InterruptedException e) {
log(startTime, "was interrupted!");
}
}
}, 5, TimeUnit.SECONDS);
}
catch (TimeoutException e) {
log(startTime, "got timeout!");
}
log(startTime, "end of main method!");
}
private static void log(long startTime, String msg) {
long elapsedSeconds = (System.currentTimeMillis() - startTime);
System.out.format("%1$5sms [%2$16s] %3$s\n", elapsedSeconds, Thread.currentThread().getName(), msg);
}
Output from running the sample code on my machine:
0ms [ main] calling runWithTimeout!
13ms [ pool-1-thread-1] starting sleep!
5015ms [ main] got timeout!
5016ms [ main] end of main method!
5015ms [ pool-1-thread-1] was interrupted!
Yes, but its generally a very bad idea to force another thread to interrupt on a random line of code. You would only do this if you intend to shutdown the process.
What you can do is to use Thread.interrupt() for a task after a certain amount of time. However, unless the code checks for this it won't work. An ExecutorService can make this easier with Future.cancel(true)
Its much better for the code to time itself and stop when it needs to.
If it is test code you want to time, then you can use the time attribute:
#Test(timeout = 1000)
public void shouldTakeASecondOrLess()
{
}
If it is production code, there is no simple mechanism, and which solution you use depends upon whether you can alter the code to be timed or not.
If you can change the code being timed, then a simple approach is is to have your timed code remember it's start time, and periodically the current time against this. E.g.
long startTime = System.currentTimeMillis();
// .. do stuff ..
long elapsed = System.currentTimeMillis()-startTime;
if (elapsed>timeout)
throw new RuntimeException("tiomeout");
If the code itself cannot check for timeout, you can execute the code on another thread, and wait for completion, or timeout.
Callable<ResultType> run = new Callable<ResultType>()
{
#Override
public ResultType call() throws Exception
{
// your code to be timed
}
};
RunnableFuture<ResultType> future = new FutureTask<>(run);
ExecutorService service = Executors.newSingleThreadExecutor();
service.execute(future);
ResultType result = null;
try
{
result = future.get(1, TimeUnit.SECONDS); // wait 1 second
}
catch (TimeoutException ex)
{
// timed out. Try to stop the code if possible.
future.cancel(true);
}
service.shutdown();
}
I can suggest two options.
Within the method, assuming it is looping and not waiting for an external event, add a local field and test the time each time around the loop.
void method() {
long endTimeMillis = System.currentTimeMillis() + 10000;
while (true) {
// method logic
if (System.currentTimeMillis() > endTimeMillis) {
// do some clean-up
return;
}
}
}
Run the method in a thread, and have the caller count to 10 seconds.
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
method();
}
});
thread.start();
long endTimeMillis = System.currentTimeMillis() + 10000;
while (thread.isAlive()) {
if (System.currentTimeMillis() > endTimeMillis) {
// set an error flag
break;
}
try {
Thread.sleep(500);
}
catch (InterruptedException t) {}
}
The drawback to this approach is that method() cannot return a value directly, it must update an instance field to return its value.
EDIT: Peter Lawrey is completely right: it's not as simple as interrupting a thread (my original suggestion), and Executors & Callables are very useful ...
Rather than interrupting threads, you could set a variable on the Callable once the timeout is reached. The callable should check this variable at appropriate points in task execution, to know when to stop.
Callables return Futures, with which you can specify a timeout when you try to 'get' the future's result. Something like this:
try {
future.get(timeoutSeconds, TimeUnit.SECONDS)
} catch(InterruptedException e) {
myCallable.setStopMeAtAppropriatePlace(true);
}
See Future.get, Executors, and Callable ...
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Future.html#get-long-java.util.concurrent.TimeUnit-
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Callable.html
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newFixedThreadPool%28int%29
I created a very simple solution without using any frameworks or APIs. This looks more elegant and understandable. The class is called TimeoutBlock.
public class TimeoutBlock {
private final long timeoutMilliSeconds;
private long timeoutInteval=100;
public TimeoutBlock(long timeoutMilliSeconds){
this.timeoutMilliSeconds=timeoutMilliSeconds;
}
public void addBlock(Runnable runnable) throws Throwable{
long collectIntervals=0;
Thread timeoutWorker=new Thread(runnable);
timeoutWorker.start();
do{
if(collectIntervals>=this.timeoutMilliSeconds){
timeoutWorker.stop();
throw new Exception("<<<<<<<<<<****>>>>>>>>>>> Timeout Block Execution Time Exceeded In "+timeoutMilliSeconds+" Milli Seconds. Thread Block Terminated.");
}
collectIntervals+=timeoutInteval;
Thread.sleep(timeoutInteval);
}while(timeoutWorker.isAlive());
System.out.println("<<<<<<<<<<####>>>>>>>>>>> Timeout Block Executed Within "+collectIntervals+" Milli Seconds.");
}
/**
* #return the timeoutInteval
*/
public long getTimeoutInteval() {
return timeoutInteval;
}
/**
* #param timeoutInteval the timeoutInteval to set
*/
public void setTimeoutInteval(long timeoutInteval) {
this.timeoutInteval = timeoutInteval;
}
}
example :
try {
TimeoutBlock timeoutBlock = new TimeoutBlock(10 * 60 * 1000);//set timeout in milliseconds
Runnable block=new Runnable() {
#Override
public void run() {
//TO DO write block of code to execute
}
};
timeoutBlock.addBlock(block);// execute the runnable block
} catch (Throwable e) {
//catch the exception here . Which is block didn't execute within the time limit
}
This was so much useful for me when i had to connect to a FTP account. Then download and upload stuff. sometimes FTP connection hangs or totally breaks. This caused whole system to go down. and i needed a way to detect it and prevent it from happening . So i created this and used it. Works pretty well.
I faced a similar kind of issue where my task was to push a message to SQS within a particular timeout. I used the trivial logic of executing it via another thread and waiting on its future object by specifying the timeout. This would give me a TIMEOUT exception in case of timeouts.
final Future<ISendMessageResult> future =
timeoutHelperThreadPool.getExecutor().submit(() -> {
return getQueueStore().sendMessage(request).get();
});
try {
sendMessageResult = future.get(200, TimeUnit.MILLISECONDS);
logger.info("SQS_PUSH_SUCCESSFUL");
return true;
} catch (final TimeoutException e) {
logger.error("SQS_PUSH_TIMEOUT_EXCEPTION");
}
But there are cases where you can't stop the code being executed by another thread and you get true negatives in that case.
For example - In my case, my request reached SQS and while the message was being pushed, my code logic encountered the specified timeout. Now in reality my message was pushed into the Queue but my main thread assumed it to be failed because of the TIMEOUT exception.
This is a type of problem which can be avoided rather than being solved. Like in my case I avoided it by providing a timeout which would suffice in nearly all of the cases.
If the code you want to interrupt is within you application and is not something like an API call then you can simply use
future.cancel(true)
However do remember that java docs says that it does guarantee that the execution will be blocked.
"Attempts to cancel execution of this task. This attempt will fail if the task has already completed, has already been cancelled,or could not be cancelled for some other reason. If successful,and this task has not started when cancel is called,this task should never run. If the task has already started,then the mayInterruptIfRunning parameter determines whether the thread executing this task should be interrupted inan attempt to stop the task."
If you want a CompletableFuture way you could have a method like
public MyResponseObject retrieveDataFromEndpoint() {
CompletableFuture<MyResponseObject> endpointCall
= CompletableFuture.supplyAsync(() ->
yourRestService.callEnpoint(withArg1, withArg2));
try {
return endpointCall.get(10, TimeUnit.MINUTES);
} catch (TimeoutException
| InterruptedException
| ExecutionException e) {
throw new RuntimeException("Unable to fetch data", e);
}
}
If you're using spring, you could annotate the method with a #Retryable so that it retries the method three times if an exception is thrown.
Instead of having the task in the new thread and the timer in the main thread, have the timer in the new thread and the task in the main thread:
public static class TimeOut implements Runnable{
public void run() {
Thread.sleep(10000);
if(taskComplete ==false) {
System.out.println("Timed Out");
return;
}
else {
return;
}
}
}
public static boolean taskComplete = false;
public static void main(String[] args) {
TimeOut timeOut = new TimeOut();
Thread timeOutThread = new Thread(timeOut);
timeOutThread.start();
//task starts here
//task completed
taskComplete =true;
while(true) {//do all other stuff }
}
There is a hacky way to do it.
Set some boolean field to indicate whether the work was completed. Then before the block of code, set a timer to run a piece of code after your timeout. The timer will check if the block of code had finished executing, and if not, throw an exception. Otherwise it will do nothing.
The end of the block of code should, of course, set the field to true to indicate the work was done.
There's a very simple option that nobody's mentioned yet:
Duration timeout = Duration.ofMinutes(5);
Thread thread = new Thread(() -> {
// your code here
});
thread.start();
thread.join(timeout.toMillis());
if (thread.isAlive()) {
thread.interrupt();
throw new MyTimeoutException();
}
If the thread running your code block fails to complete within the timeout, it is interrupted and whatever exception you want can be thrown.
It is possible to write code that will simply ignore the interruption and carry on. If you're dealing with this can cannot fix it then there is thread.stop(), but that can break any synchronisation mechanisms that you are relying on. See its deprecation notice.
You can also capture exceptions from the thread:
AtomicReference<Throwable> uncaughtException = new AtomicReference<>();
thread.setUncaughtExceptionHandler((t, ex) -> uncaughtException.setRelease(ex));
// ...
Throwable ex = uncaughtException.getAcquire();
if (ex != null) {
throw ex;
}
I had this problem too, my logs print out with ‘’Unexpected end of stream‘’.and ‘’Could not get a resource from the pool‘’,
I set the timeout of brpop to 30s, redis to 31s, and mysql database connection pool to 300s. For now, this error is not printed on the log, but I don't know if this error will be reported in the future.I don't know if it has a bad effect on my writing to the database

Thread end listener. Java

Are there any Listeners in Java to handle that some thread have been ended?
Something like this:
Future<String> test = workerPool.submit(new TestCalalble());
test.addActionListener(new ActionListener()
{
public void actionEnd(ActionEvent e)
{
txt1.setText("Button1 clicked");
}
});
I know, that it is impossible to deal like this, but I want to be notified when some thread ended.
Usually I used for this Timer class with checking state of each Future. but it is not pretty way.
Thanks
There is CompletionService you can use.
CompletionService<Result> ecs
= new ExecutorCompletionService<Result>(e);
ecs.submit(new TestCallable());
if (ecs.take().get() != null) {
// on finish
}
Another alternative is to use ListenableFuture from Guava.
Code example:
ListenableFuture future = Futures.makeListenable(test);
future.addListener(new Runnable() {
public void run() {
System.out.println("Operation Complete.");
try {
System.out.println("Result: " + future.get());
} catch (Exception e) {
System.out.println("Error: " + e.message());
}
}
}, exec);
Personally, I like Guava solution better.
No. Such listener does not exist.
But you have 2 solutions.
Add code that notifies you that thread is done in the end of run() method
Use Callable interface that returns result of type Future. You can ask Future what the status is and use blocked method get() to retrieve result
Here is a geekish listener. Highly unadvisible to use but, funny and clever
Thread t = ...
t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler(){
#Override
public void uncaughtException(Thread t, Throwable e) {
t.getThreadGroup().uncaughtException(t, e);//this is the default behaviour
}
protected void finalize() throws Throwable{
//cool, we go notified
//handle the notification, but be worried, it's the finalizer thread w/ max priority
}
});
The effect can be achived via PhantomRefernce better
hope you have a little smile :)
Side note: what you ask is NOT thread end, but task completion event and the best is overriding either decorateTask or afterExecute
Without adding a lot of extra code you can make a quick listener thread yourself as follows:
//worker thread for doings
Thread worker = new Thread(new Runnable(){
public void run(){/*work thread stuff here*/}
});
worker.start();
//observer thread for notifications
new Thread(new Runnable(){
public void run(){
try{worker.join();}
catch(Exception e){;}
finally{ /*worker is dead, do notifications.*/}
}).start();
You can implement Observer Pattern to report completion.
public interface IRunComplete {
public void reportCompletion(String message);
}
Let the Thread caller implement this interface.
and in run() method you call this method at the end. So now you exactly knows when this thread gonna end.
Try it. I am actually using this and it's working fine.
You have a join() method defined by Thread class for that. However, you don't have direct visibility to a thread executing your Callable in concurrency API case..
Use this Example:
public class Main {
public static void main(String[] args) {
CompletionListener completedListener = count -> System.out.println("Final Count Value: " + count);
HeavyWorkRunnable job = new HeavyWorkRunnable(completedListener);
Thread otherThread = new Thread(job);
otherThread.start();
}
static class HeavyWorkRunnable implements Runnable {
CompletionListener completionListener;
public HeavyWorkRunnable(CompletionListener completionListener) {
this.completionListener = completionListener;
}
#Override
public void run() {
int count = 0;
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Clock Tick #"+i);
count += 1;
}
if (completionListener != null) {
completionListener.onCompleted(count);
}
}
}
#FunctionalInterface
interface CompletionListener {
void onCompleted(int count);
}
}

How to synchronize/lock correctly when using CountDownLatch

It boils down to one thread submitting job via some service. Job is executed in some TPExecutor. Afterwards this service checks for results and throw exception in original thread under certain conditions (job exceeds maximum number of retries, etc.). Code snippet below roughly illustrate this scenario in legacy code:
import java.util.concurrent.CountDownLatch;
public class IncorrectLockingExample {
private static class Request {
private final CountDownLatch latch = new CountDownLatch(1);
private Throwable throwable;
public void await() {
try {
latch.await();
} catch (InterruptedException ignoredForDemoPurposes) {
}
}
public void countDown() {
latch.countDown();
}
public Throwable getThrowable() {
return throwable;
}
public void setThrowable(Throwable throwable) {
this.throwable = throwable;
}
}
private static final Request wrapper = new Request();
public static void main(String[] args) throws InterruptedException {
final Thread blockedThread = new Thread() {
public void run() {
wrapper.await();
synchronized (wrapper) {
if (wrapper.getThrowable() != null)
throw new RuntimeException(wrapper.getThrowable());
}
}
};
final Thread workingThread = new Thread() {
public void run() {
wrapper.setThrowable(new RuntimeException());
wrapper.countDown();
}
};
blockedThread.start();
workingThread.start();
blockedThread.join();
workingThread.join();
}
}
Sometimes, (not reproducible on my box, but happens on 16 core server box) exception isn't getting reported to original thread. I think this is because happens-before is not forced(eg. 'countDown' happens before 'setThrowable') and program continues to work(but should fail).
I would appreciate any help about how to resolve this case.
Constraints are: release in a week, minimum impact on existing codebase is needed.
The code above (as now updated) should work as you expected without the use of further synchronisation mechanisms. The memory barrier and its corresponding 'happens-before' relationship is enforced by the use of the CountDownLatch await() and countdown() methods.
From the API docs:
Actions prior to "releasing" synchronizer methods such as Lock.unlock, Semaphore.release, and CountDownLatch.countDown happen-before actions subsequent to a successful "acquiring" method such as Lock.lock, Semaphore.acquire, Condition.await, and CountDownLatch.await on the same synchronizer object in another thread.
If you are dealing with concurrency on a regular basis get yourself a copy of 'Java Concurrency in Practice', it's the Java concurrency bible and will be well worth its weight on your bookshelf :-).
I suspect you need
private volatile Throwable throwable
Have you tried using an ExecutorService as it is built in and does this for you. The following prints
future1 := result
future2 threw java.lang.IllegalStateException
future3 timed out
The code is
public static void main(String... args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future1 = executor.submit(new Callable<String>() {
public String call() throws Exception {
return "result";
}
});
Future<String> future2 = executor.submit(new Callable<String>() {
public String call() throws Exception {
throw new IllegalStateException();
}
});
Future<String> future3 = executor.submit(new Callable<String>() {
public String call() throws Exception {
Thread.sleep(2000);
throw new AssertionError();
}
});
printResult("future1", future1);
printResult("future2", future2);
printResult("future3", future3);
executor.shutdown();
}
private static void printResult(String description, Future<String> future) {
try {
System.out.println(description+" := "+future.get(1, TimeUnit.SECONDS));
} catch (InterruptedException e) {
System.out.println(description+" interrupted");
} catch (ExecutionException e) {
System.out.println(description+" threw "+e.getCause());
} catch (TimeoutException e) {
System.out.println(description+" timed out");
}
}
In the code for FutureTask, there is a comment.
/**
* The thread running task. When nulled after set/cancel, this
* indicates that the results are accessible. Must be
* volatile, to ensure visibility upon completion.
*/
If you are not going to re-use the code in the JDK, it can still be worth reading it so you can pick up on any tricks they use.

Categories

Resources