Java: Design Ideas for Stopping Callable Thread - java

I am writing a program that does some batch processing. The batch elements can be processed independently of each other and we want to minimize overall processing time. So, instead of looping through each element in the batch one at a time, I am using an ExecutorService and submitting Callable objects to it:
public void process(Batch batch)
{
ExecutorService execService = Executors.newCachedThreadPool();
CopyOnWriteArrayList<Future<BatchElementStatus>> futures = new CopyOnWriteArrayList<Future<BatchElementStatus>>();
for (BatchElement element : batch.getElement())
{
Future<MtaMigrationStatus> future = execService.submit(new ElementProcessor(batch.getID(),
element));
futures.add(future);
}
boolean done = false;
while (!done)
{
for (Future<BatchElementStatus> future : futures)
{
try
{
if (future.isDone())
{
futures.remove(future);
}
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
if (futures.size() == 0)
{
done = true;
}
}
}
}
We want to be able to allow the batch processing to be cancelled. Because I'm not using a loop, I can't just check at the top each loop if a cancel flag has been set.
We are using a JMS topic to which both the BatchProcessor and ElementProcessor will be listening to inform them the batch has been cancelled.
There are a number of steps in the ElementProcess call() after which some of them the processing can be safely stopped but there's a point of no return. The class has this basic design:
public class ElementProcessor implements Callable, MessageListener
{
private cancelled = false;
public void onMessage(Message msg)
{
// get message object
cancelled = true;
}
public BatchElementStatus call()
{
String status = SUCCESS;
if (!cancelled)
{
doSomehingOne();
}
else
{
doRollback();
status = CANCELLED;
}
if (!cancelled)
{
doSomehingTwo();
}
else
{
doRollback();
status = CANCELLED;
}
if (!cancelled)
{
doSomehingThree();
}
else
{
doRollback();
status = CANCELLED;
}
if (!cancelled)
{
doSomehingFour();
}
else
{
doRollback();
status = CANCELLED;
}
// After this point, we cannot cancel or pause the processing
doSomehingFive();
doSomehingSix();
return new BatchElementStatus("SUCCESS");
}
}
I'm wondering if there's a better way to check if the batch/element has been cancelled other than wrapping method calls/blocks of code in the call method in the if(!cancelled) statements.
Any suggestions?

I don't think you can do much better than what you are currently doing, but here is an alternative:
public BatchElementStatus call() {
return callMethod(1);
}
private callMethod(int methodCounter) {
if (cancelled) {
doRollback();
return new BatchElementStatus("FAIL");
}
switch (methodCounter) {
case 1 : doSomethingOne(); break;
case 2 : doSomethingTwo(); break;
...
case 5 : doSomethingFive();
doSomethingSix();
return new BatchElementStatus("SUCCESS");
}
return callMethod(methodCounter + 1);
}
Also, you want to make cancelled volatile, since onMessage will be called from another thread. But you probably don't want to use onMessage and cancelled anyway (see below).
Other minor points: 1) CopyOnWriteArrayList<Future<BatchElementStatus>> futures should just be an ArrayList. Using a concurrent collection mislead us into thinking that futures is on many thread. 2) while (!done) should be replaced by while (!futures.isEmpty()) and done removed. 3) You probably should just call future.cancel(true) instead of "messaging" cancellation. You would then have to check if (Thread.interrupted()) instead of if (cancelled). If you want to kill all futures then just call execService.shutdownNow(); your tasks have to handle interrupts for this to work.
EDIT:
instead of your while(!done) { for (... futures) { ... }}, you should use an ExecutorCompletionService. It does what you are trying to do and it probably does it a lot better. There is a complete example in the API.

Future has a cancel(boolean) method that will interrupt the running thread if true is passed in
so replace the if(!cancelled) checks with if(Thread.interrupted()) and return when you got a interrupt (you're not currently)
note that this will reset the interrupted flag to false (so if(Thread.interrupted()&&Thread.interrupted()) will be false) if you don't want to reset it use Thread.currentThread().isInterrupted() this maintains the flag for subsequent checks
or you can reset the flag to interrupted with Thread.currentThread().interrupt();
besides that use this inside the waiting while
for(Iterator<Future<MtaMigrationStatus>> it = futures.iterator();it.hasNext();){
Future<MtaMigrationStatus> future = it.next();
try
{
if (future.isDone())
{
it.remove();//<<--this avoids concurrent modification exception in the loop
}
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
}
if (futures.size() == 0)//outside the inner for loop and inside the while (or make the condition this) for micro-optimizing this check
{
done = true;
}

Your ElementProcessor can extend from java.util.concurrent.FutureTask which is
A cancellable asynchronous computation. This class provides a base
implementation of Future, with methods to start and cancel a
computation, query to see if the computation is complete, and retrieve
the result of the computation.
The FutureTask class is an implementation of Future that implements
Runnable, and so may be executed by an Executor.
FutureTask has a cancel method which you can implement to do some cancel specific operations. Also, if FutureTask is canceled it will not be executed anymore, so you don't have to check always the status.

Related

How can I check if all tasks have been completed (normally or abruptly)?

I have the following class:
public class Service{
private static final ExecutorService executor = Executors.newFixedThreadPool(4);
public synchronized void execute(Collection<Runnable> runs){
for(Runnable r: runs){
executor.execute(r);
}
}
public boolean isComplete(){
//should return true iff all tasks applied by the execute(Collection<Runnable> runs)
//method're finished their execution (normally or abruptly,
//it doesn matter)
}
}
How can I implement the isComplete() method. I need to check if there's a task that is currently in progress. If the executor is cleared(all tasks are completed) then the method should return true, otherwise return false.
Given that you are using ExecutorService you could use submit instead of execute and store the returned Future in a list. Then inside isComplete() iterate through all of the Futures and call isDone() on each one. (This approach will also let you cancel the submitted tasks if required, through the Futures).
For example † :
class Service{
private static final ExecutorService executor = Executors.newFixedThreadPool(4);
private List<Future<?>> futures;
public void execute(Collection<Runnable> runs){
futures = runs.stream()
.map(r -> executor.submit(r))
.collect(Collectors.toList());
}
public boolean isComplete(){
for (Future<?> future : futures)
if (!future.isDone()) return false;
return true;
}
}
Depending on your use case, you may get better performance by removing items from the futures list as you go, but you (may) need to sync the isComplete method:
public synchronized boolean isComplete(){
Iterator<Future<?>> itr = futures.iterator();
while (itr.hasNext()) {
if (itr.next().isDone()) itr.remove();
else return false;
}
return true;
}
† As this code sample is written, it assumes that you will only make one call to execute per instance of Service, so it does not need to be synchronized. If you will have multiple concurrent callers to execute on each Service instance then note that this will replace the futures list on each call to execute. You could handle that by making the class single-use only, or by appending to futures. It depends entirely on your use-case.
You can call the shutdown() method to ask the executor to terminate all threads and shutdown the pool. And then call isTerminated() which will return true if all threads are terminated.
If you want to block execution, you can use the awaitTerminationMethod(), and finally shutDownNow() will terminate the pool regardless if the threads have completed execution or not.
CountDownLatch solved my problem.
ExecutorService WORKER_THREAD_POOL
= Executors.newFixedThreadPool(10);
CountDownLatch latch = new CountDownLatch(2);
for (int i = 0; i < 2; i++) {
WORKER_THREAD_POOL.submit(() -> {
try {
// ...
latch.countDown();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
// wait for the latch to be decremented by the two remaining threads
latch.await();

Execute Runnable, Timeout, then Retry

I am using the Ebay API to place a bid on an item. If there is some kind of network error so that the API call does not return, I want to retry the call immediately afterwards. It seems so simple but I've been going round in circles all day. I'm not really experienced with threading. Is this how it's supposed to work or am I totally wrong?
Here is the Callable class:
public class PlaceOfferThread implements Callable<Boolean> {
private PlaceOfferCall call;
public Boolean isComplete;
public PlaceOfferThread (PlaceOfferCall p) {
call = p;
}
#Override
public Boolean call() throws Exception {
try {
call.placeOffer();
return true;
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
return false;
}
}
And here is the caller
int timeout = 10;
int maxRetries = 5;
int retries = 0;
ExecutorService executor = Executors.newSingleThreadExecutor();
PlaceOfferThread thread = new PlaceOfferThread(call);
boolean flag = false;
while (!flag && retries++ < maxRetries) {
Future<Boolean> future = null;
try {
future = executor.submit(thread);
flag = future.get(timeout, TimeUnit.SECONDS);
future.cancel(true);
}
catch(TimeoutException ex) {
// no response from Ebay, potential network issues
// resubmit the call to Ebay with the same invocation id
future.cancel(true);
}
catch (Exception threadException) {
// any other exception indicates that we got a response from Ebay
// it just wasn't the response we wanted
throw new Exception(threadException.getMessage());
}
}
executor.shutdown(); // TODO
If there is some kind of network error so that the API call does not return, I want to retry the call immediately afterwards.
I'm not 100% sure how your application is working right now but here are some thoughts:
When you call future.cancel(true) you most likely will not be stopping the current transaction. Unless you are using NIO calls, IO methods are not interruptible. Interrupting a thread just sets a flag on the thread and caused those few methods that throw InterruptedException (like sleep, wait, join) to do so. You'll have to watch the Thread.currentThread().isInterrupted() method to be able to see the interrupt otherwise.
I think the right thing to do is to set the connection and IO timeouts of the underlying http-client object and have it throw or exit with an error if there are problems. Trying to kill it from another thread is going to be much more difficult.
In looking at your code I'm not sure why you are using threads at all. Maybe you are doing other processing but it might be better to make the call directly. Then you can tune the HttpClient's IO timeouts and handle them appropriately.

How can I interrupt Callables in an AsyncTask when the AsyncTask.cancel() method is invoked?

My Activity has an AsyncTask whose doInBackground method you can see below. I have to make multiple search request to multiple servers and in order to speed up the execution I've used Java's ExecutorService to make concurrent requests.
This works fine but I'd like my AsyncTask to stop whatever it is doing and quit, if I call the AsyncTask.cancel(); method with true as the mayInterruptIfRunning parameter. This is useful in situations where I need to stop the task when my Activity exits e.g. the "Back" button is pressed.
I've read that calling the cancel() method of the AsyncTask will prevent the onPostExecute method from being invoked, but the doInBackground will run until it is finished.
Is there a way, I could interrupt my Callables and force them to stop whatever it is they are doing and stop the AsyncTask.
I have posted an abridged version of my code here for brevity, but I have a bunch of a Callables, not just one.
Thanks.
protected ArrayList<Result> doInBackground(final String... strQuery) {
ArrayList<Result> objResults = new ArrayList<Result>();
ExecutorService esrExecutor = Executors.newFixedThreadPool(2);
Set<Callable<ArrayList<Result>>> setCallables = new HashSet<Callable<ArrayList<Result>>>();
setCallables.add(new Callable<ArrayList<Result>>() {
public ArrayList<Result> call() throws Exception {
try {
MySearcher objSearcher = new MySearcher(Finder.this.objContext);
ArrayList<Result> objResults = new ArrayList<Result>();
objResults = objSearcher.doSearch(strQuery[0]);
return objResults;
} catch (Indexer.LoginException e) {
return null;
}
return null;
}
});
List<Future<ArrayList<Result>>> lstFutures;
try {
lstFutures = esrExecutor.invokeAll(setCallables);
for(Future<ArrayList<Result>> futFuture : lstFutures){
if (futFuture.get().isEmpty() == false)
objResults.addAll(futFuture.get());
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
esrExecutor.shutdown();
return objResults;
}
I think that one solution would be to check for isCancelled() regularly in your doInBackground() method to check if the AsyncTask was cancelled and if you need to stop what you are doing earlier.
Here is the place you iterate and wait:
for(Future<ArrayList<Result>> futFuture : lstFutures){
if (futFuture.get().isEmpty() == false)
objResults.addAll(futFuture.get());
}
the get() method for Future, Waits if necessary for the computation to complete, and then retrieves its result.
you can check isCancelled() like this,
for(Future<ArrayList<Result>> futFuture : lstFutures){
if(isCancelled())
break;
else if (futFuture.get().isEmpty() == false)
objResults.addAll(futFuture.get());
}
if(isCancelled())esrExecutor.shutdownNow();
Another option, if for example doSearch has a loop you could do it manually without the use of isCancelled or cancel. Your MySearcher class could have the following.
//in your MySearcher class
private AtomicBoolean cancelled = false;
public ArrayList<Result> doSearch(...){
while(notFound && !cancelled.get()){
// keep searching
}
}
public void cancel(){
cancelled.set(true);
}
now you can call cancel from anywhere.

Waiting for an unknown number of asynchronous tasks

I have a queue of tasks, and a thread that peek the queue once in a few seconds and if there is a task it performs it.
I have another code section (in another thread of course), that creates tasks in a loop (I can't know the number of tasks in advance from outside the loop) and insert them to the queue. The tasks contains some 'result' object, and the external thread (which created those tasks) need to wait for all the tasks to finish and finally get the result from each one of them.
The problem is that I can't pass java Semaphore\CountDownLatch etc to the result object since I don't know the number of monitors in advance.
I also can't use an Executor that uses invokeAll or wait for the Future object since the tasks are unsynchrnized (the external thread just pust the task to a queue and another thread will execute the task when he have time for this).
The only solution I've had in mind is to create some 'Inverted Semaphore' class that holds a set of results and a monitors counter. The getResult function will check if the counter == 0 and if the answer is yes will notify some lock object, and the getResult function will wait for this lock:
public class InvertedSemaphore<T> {
Set<T> resultSet;
int usages;
final Object c;
public InvertedSemaphore() {
resultSet = Collections.synchronizedSet(new HashSet<T>());
usages = 0;
c = new Object();
}
public void addResult(T result) {
resultSet.add(result);
}
public void addResults(Set<T> result) {
resultSet.addAll(result);
}
public void acquire() {
usages++;
}
public void release() {
synchronized (c) {
if (--usages == 0) {
c.notify();
}
}
}
public Set<T> getResults() {
synchronized (c) {
try {
while (usages > 0) {
c.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return resultSet;
}
}
Each addTask method will invoke semaphore.acquire, and each of the (unsynchronized) tasks will invoke semaphore.release in the end of the task.
It sounds pretty complicated and I'm pretty sure there is a better solution for this in java concurrent library or something.
Any idea will be appriciated:)
If the tasks don't need to be processed in order, use an ExecutorCompletionService
More generally, it is not necessary to use invokeAll on an ExecutorService in order to get a Future for the result. ExecutorService#submit could be used for this purpose, or optionally, the task being created could implement Future itself, thus allowing the creator of the task to ask for the result at a later point in time.
Some code:
class MyTask {
AtomicReference<?> result = new AtomicReference<?>();
void run() {
//do stuff here
result.set(/* the result of the calculation */);
}
boolean resultReady() {
return result.get()!=null;
}
? get() {
return result.get();
}
}
... elsewhere in code
void createTasks() {
Collection<MyTask> c = new ...;
while(indeterminable condition) {
MyTask task = new MyTask();
c.add(task);
mysteryQueue.add(task);
}
while(haven't received all results) {
MyTask task = c.get(...); //or iterate or whatever
? result = task.get();
if (result!=null) {
//do stuff, probably remove the task from the collection c would be smart
}
}
}
One idea would be to use a separate queue for the results.
So you will have one blocking queue that thread A places tasks for thread B thereby having a producer-consumer approach, and when each task is completed, the result could be placed in the second result queue inverting the consumer-producer roles since now thread A that originally created the tasks will consume the result from the second queue.
You can do the following:
each producer will hold its own queue. The producer will pass a means to report to this queue to the Task itself. When the task finishes running, it will queue its result to this queue. It is beast described by some code:
class Result{}
interface IResultCallback{
void resultReady(Result r); // this is an abstraction of the queue
}
class Producer implements IResultCallback{
// the producer needs to pass itself to the constructor of the task,
// the task will only see its "resultReady" facade and will be able to report to it.
// the producer can aggragte the results at it will and execute its own computation as
// as soon it is ready
Queue<Result> results; // = init queue
#Override
public void resultReady(Result r) {
results.add(r);
if(results.size() == 9){
operate();
}
results.clear();
}
public void operate(){
// bla bla
}
}
public class Task {
IResultCallback callback;
public Task(IResultCallback callback){
this.callback = callback;
}
public void execute(){
// bla bla
Result r = null; // init result;
callback.resultReady(r);
}
}

Stopping looping thread in Java

I'm using a thread that is continuously reading from a queue.
Something like:
public void run() {
Object obj;
while(true) {
synchronized(objectsQueue) {
if(objectesQueue.isEmpty()) {
try {
objectesQueue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
obj = objectesQueue.poll();
}
}
// Do something with the Object obj
}
}
What is the best way to stop this thread?
I see two options:
1 - Since Thread.stop() is deprecated, I can implement a stopThisThread() method that uses a n atomic check-condition variable.
2 - Send a Death Event object or something like that to the queue. When the thread fetches a death event, it exits.
I prefer the 1st way, however, I don't know when to call the stopThisThread() method, as something might be on it's way to the queue and the stop signal can arrive first (not desirable).
Any suggestions?
The DeathEvent (or as it is often call, "poison pill") approach works well if you need to complete all of the work on the queue before shutting down. The problem is that this could take a long time.
If you want to stop as soon as possible, I suggest you do this
BlockingQueue<O> queue = ...
...
public void run() {
try {
// The following test is necessary to get fast interrupts. If
// it is replaced with 'true', the queue will be drained before
// the interrupt is noticed. (Thanks Tim)
while (!Thread.interrupted()) {
O obj = queue.take();
doSomething(obj);
}
} catch (InterruptedException ex) {
// We are done.
}
}
To stop the thread t that instantiated with that run method, simply call t.interrupt();.
If you compare the code above with other answers, you will notice how using a BlockingQueue and Thread.interrupt() simplifies the solution.
I would also claim that an extra stop flag is unnecessary, and in the big picture, potentially harmful. A well-behaved worker thread should respect an interrupt. An unexpected interrupt simply means that the worker is being run in a context that the original programmer did not anticipate. The best thing is if the worker to does what it is told to do ... i.e. it should stop ... whether or not this fits with the original programmer's conception.
Why not use a scheduler which you simply can stop when required? The standard scheduler supports repeated scheduling which also waits for the worker thread to finish before rescheduling a new run.
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
service.scheduleWithFixedDelay(myThread, 1, 10, TimeUnit.SECONDS);
this sample would run your thread with a delay of 10 sec, that means when one run finishes, it restarts it 10 seconds later. And instead of having to reinvent the wheel you get
service.shutdown()
the while(true) is not necessary anymore.
ScheduledExecutorService Javadoc
In your reader thread have a boolean variable stop. When you wish for this thread to stop set thius to true and interrupt the thread. Within the reader thread when safe (when you don't have an unprocessed object) check the status of the stop variable and return out of the loop if set. as per below.
public class readerThread extends Thread{
private volitile boolean stop = false;
public void stopSoon(){
stop = true;
this.interrupt();
}
public void run() {
Object obj;
while(true) {
if(stop){
return;
}
synchronized(objectsQueue) {
if(objectesQueue.isEmpty()) {
try {
objectesQueue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
if(stop){
return;
}
obj = objectesQueue.poll();
// Do something with the Object obj
}
}
}
}
public class OtherClass{
ThreadReader reader;
private void start(){
reader = ...;
reader.start();
}
private void stop(){
reader.stopSoon();
reader.join(); // Wait for thread to stop if nessasery.
}
}
Approach 1 is the preferred one.
Simply set a volatile stop field to true and call interrupt() on the running thread. This will force any I/O methods that wait to return with an InterruptedException (and if your library is written correctly this will be handled gracefully).
I think your two cases actually exhibit the same potential behavior. For the second case consider Thread A adds the DeathEvent after which Thread B adds a FooEvent. When your job Thread receives the DeathEvent there is still a FooEvent behind it, which is the same scenario you are describing in Option 1, unless you try to clear the queue before returning, but then you are essentially keeping the thread alive, when what you are trying to do is stop it.
I agree with you that the first option is more desirable. A potential solution would depend on how your queue is populated. If it is a part of your work thread class you could have your stopThisThread() method set a flag that would return an appropriate value (or throw Exception) from the enqueuing call i.e.:
MyThread extends Thread{
boolean running = true;
public void run(){
while(running){
try{
//process queue...
}catch(InterruptedExcpetion e){
...
}
}
}
public void stopThisThread(){
running = false;
interrupt();
}
public boolean enqueue(Object o){
if(!running){
return false;
OR
throw new ThreadNotRunningException();
}
queue.add(o);
return true;
}
}
It would then be the responsibility of the object attempting to enqueue the Event to deal with it appropriately, but at the least it will know that the event is not in the queue, and will not be processed.
I usually put a flag in the class that has the Thread in it and in my Thread code I would do. (NOTE: Instead of while(true) I do while(flag))
Then create a method in the class to set the flag to false;
private volatile bool flag = true;
public void stopThread()
{
flag = false;
}
public void run() {
Object obj;
while(flag) {
synchronized(objectsQueue) {
if(objectesQueue.isEmpty()) {
try {
objectesQueue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
obj = objectesQueue.poll();
}
}
// Do something with the Object obj
}
}

Categories

Resources