ExecutorService invokeall threadpool issue - java

I am struggling with a use case where one of the tasks submitted to invokeall() throws CancellationException forcing program NOT to terminate. How can make sure this program will terminate properly in case of CancellationException ?
How I am finding out my program not terminated clean? I am using netbeans and shows progress bar at bottom right if program doesn't terminate.
Here is code:
int poolSize = Runtime.getRuntime().availableProcessors();
ExecutorService pool = Executors.newFixedThreadPool(poolSize);
Set<Callable<Object>> tasksSet = new HashSet<>();
tasksSet.add(new Task1());
tasksSet.add(new Task2());
tasksSet.add(new Task3());
List<Future<TrendLineStatisticsVO>> resultSet = pool.invokeAll(tasksSet, 1, TimeUnit.MINUTES);
for (Future<Object> future : resultSet) {
Object result;
try {
result = future.get(5, TimeUnit.SECONDS);
} catch (InterruptedException ex) {
ex.printStackTrace();
Logger.getLogger(CallableDemo.class.getName()).log(Level.SEVERE, null, ex);
} catch (ExecutionException ex) {
ex.printStackTrace();
Logger.getLogger(CallableDemo.class.getName()).log(Level.SEVERE, null, ex);
} catch (TimeoutException ex) {
ex.printStackTrace();
Logger.getLogger(CallableDemo.class.getName()).log(Level.SEVERE, null, ex);
}
}
pool.shutdown();
And Task1 code:
public class Task1 implements Callable<Object> {
#Override
public Object call() throws Exception {
//This for sure takes days to complete, so should through Cancellation exception because timeout on invokeall set to 1 minute
long val = 0;
for (long i = 0; i < Long.MAX_VALUE - 5000; i++) {
val += i;
}
return "Sucessfull Task1 object...";
}
}
Task2 and Task3 code also same except these two classes use Integer.MAX_VALUE in for loop check.

There are two issues:
1)
Per the Javadoc:
tasks that have not completed are cancelled.
So you will have to code your Task to be responsive to interruption. What is happening in the background is similar to future.cancel(true) if the tasks don't complete in the time specified, the true in the argument says to interrupt() the thread running the task. Like I mentioned, your tasks will have to look out for interruption. Something similar to:
#Override
public Object call() throws Exception {
//This for sure takes days to complete, so should through Cancellation exception because timeout on invokeall set to 1 minute
long val = 0;
for (long i = 0; i < Long.MAX_VALUE - 5000; i++) {
if(Thread.interruped()){
throw new RuntimeException("Did not complete in time: " + i);
}
val += i;
}
return "Sucessfull Task1 object...";
}
How I am finding out my program not terminated clean? I am using netbeans and shows progress bar at bottom right if program doesn't terminate.
Without my update above the program will never end as the thread pool is still running. shutdown will do nothing as the tasks haven't completed (event with cancel).
2)
A task that is cancelled, by definition, did not complete (or even start) so invoking get on the Future will fail quickly. You could ask the future if it's cancelled Future#isCancelled.

Related

Handling the Hanging Tasks [duplicate]

This question already has answers here:
ExecutorService that interrupts tasks after a timeout
(11 answers)
Closed 7 years ago.
This is just an example to explain my problem...
I am using ExecutorService with 20 active threads and 75K max queued items...
In my case, a normal task should not take more than 10 seconds, if it takes more time that means there's some problem with the task.
If all the threads are hung due to problematic tasks my RejectionHandler would restart the entire service.
I have two questions here:
I do not like the idea of restarting the service, instead if there's
way to detect hanging thread and we could just restart that hung
thread that would be great. I have gone through couple of articles to handle hung threads with ThreadManager but have not found anything
with ExecutorService.
I am very much fascinated about the Executors.newCachedThredPool()
because on peak days we are heavily loaded with incoming tasks, and
on other days they are very few. Any suggestions would be greatly
appreciated.
public class HangingThreadTest {
// ExecutorService executorService = Executors.newCachedThreadPool()
private static ExecutorService executorService = new ThreadPoolExecutor(10,
20, 5L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(75000));
public static void main(String... arg0) {
for (int i = 0; i < 50000; i++) {
executorService.submit(new Task());
}
}
}
/**
* Task to be completed
*/
class Task implements Runnable {
private static int count = 0;
#Override
public void run() {
count++;
if (count%5 == 0) {
try {
System.out.println("Hanging Thread task that needs to be reprocessed: "
+ Thread.currentThread().getName()+" count: "+count);
Thread.sleep(11000);
} catch (InterruptedException e) {
// Do something
}
}
else{
System.out.println("Normal Thread: "
+ Thread.currentThread().getName()+" count: "+count);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//Do something
}
}
}
}
There is no build-in mechanism in Executors framework that would help terminate a thread if it has been running for more than a threshold value.
But we can achieve this with some extra code as below:
Get the Future object returned by the executorService.submit(...);.
Future future = executorService.submit(new Task());
Call the get method on this future object to and make it wait only for threshold interval for task completion. Below, an example that is waits for only 2 secs.
try {
f.get(2, TimeUnit.SECONDS);
} catch (TimeoutException e) {
f.cancel(true);
} catch (Exception e) {}
The above code waits for 2 seconds for task completion it throws a TimeoutException if it doesn't get completed during that time. Subsequently we can call cancel method on the future object. This results in setting the interrupt flag in the thread that is executing the task.
Now the final change is, in the Task class code we need to check at necessary points (application dependent), whether the interrupt flag has been set to true using isInterrupted() method of Thread class. If interrupted==true, we can do the necessary clean up and return from the run method immediately. The critical piece here is to identify the necessary points in your Task class where you want to check for this interrupted flag.
This makes the thread available for processing next task.
You may have a look at this article, it was very helpful for me before when I was facing the same problem : Java Hanging Thread Detection

Not calling get on list of futures

I'm using a global Executor service with some fixed thread pool size. We have bunch of related tasks that we submit for execution and wait on list of futures.
Recently, we faced a high CPU utilization issue and on debugging I found that an exception occurred while calling get() on one of the item in list of futures. Current, we iterate over the list and there is a try catch surrounding the whole loop.
try{
List<Result> results = new ArrayList<>()
for(Future<Result> futureResult: futureResults{
Result result = futureResult.get();
results.add(result);
}
} catch(Exception e){
throw new InternalServiceException(e);
}
//Do something with results
Wanted to know the behaviour of other threads if get is never called on some of the items in future. I tried searching but was not able to find anything.
Also, can this behaviour trigger high CPU utilization ?
http://www.journaldev.com/1650/java-futuretask-example-program
I would still check if the future isDone as in the example above.
If you need to run other operations or want to utilize the CPU better then I would put the collector in a separate thread and perhaps just poll for results every minute or so.
Could be scheduled or handled by Thread.sleep.
Executors class provides various methods to execute Callable in a thread pool. Since callable tasks run in parallel, we have to wait for the returned Object.
Callable tasks return java.util.concurrent.Future object. Using Future we can find out the status of the Callable task and get the returned Object.
It provides get() method that can wait for the Callable to finish and then return the result.
There is an overloaded version of get() method where we can specify the time to wait for the result, it’s useful to avoid current thread getting blocked for longer time.
Future provides cancel() method to cancel the associated Callable task. There are isDone() and isCancelled() methods to find out the current status of associated Callable task.
Here is a simple example of Callable task that returns the name of thread executing the task after some random time.
We are using Executor framework to execute 10 tasks in parallel and use Future to get the result of the submitted tasks.
public class FutureObjectTest implements Callable<String>{
#Override
public String call() throws Exception {
long waitTime = (long) (Math.random()*10000);
System.out.println(Thread.currentThread().getName() + " waiting time in MILISECONDS " + waitTime);
Thread.sleep(waitTime);
return Thread.currentThread().getName() + " exiting call method.";
}
public static void main(String [] args){
List<Future<String>> futureObjectList = new ArrayList<Future<String>>();
ExecutorService executorService = Executors.newFixedThreadPool(5);
Callable<String> futureObjectTest = new FutureObjectTest();
for(int i=0; i<10; i++){
Future<String> futureResult = executorService.submit(futureObjectTest);
futureObjectList.add(futureResult);
}
for(Future<String> futureObj : futureObjectList){
try {
System.out.println(futureObj.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
System.out.println("Starting get method of wait");
////////////get(Timeout) method///////
futureObjectList.clear();
for(int i=0; i<10; i++){
Future<String> futureResult = executorService.submit(futureObjectTest);
futureObjectList.add(futureResult);
}
executorService.shutdown();
for(Future<String> futureObj : futureObjectList){
try {
System.out.println(futureObj.get(2000,TimeUnit.MILLISECONDS));
} catch (InterruptedException | ExecutionException | TimeoutException e) {
e.printStackTrace();
}
}
}
}

Java JNI and Future Task

I am trying to implement a code where I want to call a function from JNI which should have a timeout. If it exceeds the timeout, I want to terminate the native task. I am posting a piece of code to show as an example.
void myFunction(timeOutInSeconds)
{
if(timeOutInSeconds > 0)
{
ExecutorService executor = Executors.newCachedThreadPool();
Callable<Integer> task = new Callable<Integer>() {
public Integer call() {
System.out.println("Calling JNI Task");
JNI_Task();
System.out.println("Finished JNI Task");
return 0;
}
};
Future<Integer> future = executor.submit(task);
try
{
#SuppressWarnings("unused")
Integer result = future.get(timeOutInSeconds, TimeUnit.SECONDS);
}
catch (TimeoutException ex)
{
// handle the timeout
kill_task_in_JNI();
// future.cancel(true);
return TIMEOUT;
} catch (InterruptedException e) {
// handle the interrupts
} catch (ExecutionException e) {
// handle other exceptions
}
finally
{
// future.cancel(true);
executor.shutdown();
}
}
else
JNI_Task();
}
There are several questions -
Where should I exactly put future.cancel(). There are 2 locations which are commented.
If I run this function with timeOutInSeconds = 0, it runs perfectly.
However Irrespective of the value of timeOutInSeconds, the task gets stuck up and
the JNI task does not get called. I check this by putting printf's in the JNI
code. The task takes 1 second to execute and I gave 30 seconds, 5 minutes etc. still it
is stuck up.
Is there any problem with such approach?
You can (and in this case should) call future.cancel() only in the finally block. http://docs.oracle.com/javase/tutorial/essential/exceptions/finally.html.
About the 2nd question, its not clear for me if the problem also occur when timeOutInSeconds=0. Is this the case? Can you provide the content of the JNI_TASK() method?

When should I use a CompletionService over an ExecutorService?

I just found CompletionService in this blog post. However, this does't really showcases the advantages of CompletionService over a standard ExecutorService. The same code can be written with either. So, when is a CompletionService useful?
Can you give a short code sample to make it crystal clear? For example, this code sample just shows where a CompletionService is not needed (=equivalent to ExecutorService)
ExecutorService taskExecutor = Executors.newCachedThreadPool();
// CompletionService<Long> taskCompletionService =
// new ExecutorCompletionService<Long>(taskExecutor);
Callable<Long> callable = new Callable<Long>() {
#Override
public Long call() throws Exception {
return 1L;
}
};
Future<Long> future = // taskCompletionService.submit(callable);
taskExecutor.submit(callable);
while (!future.isDone()) {
// Do some work...
System.out.println("Working on something...");
}
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
Omitting many details:
ExecutorService = incoming queue + worker threads
CompletionService = incoming queue + worker threads + output queue
With ExecutorService, once you have submitted the tasks to run, you need to manually code for efficiently getting the results of the tasks completed.
With CompletionService, this is pretty much automated. The difference is not very evident in the code you have presented because you are submitting just one task. However, imagine you have a list of tasks to be submitted. In the example below, multiple tasks are submitted to the CompletionService. Then, instead of trying to find out which task has completed (to get the results), it just asks the CompletionService instance to return the results as they become available.
public class CompletionServiceTest {
class CalcResult {
long result ;
CalcResult(long l) {
result = l;
}
}
class CallableTask implements Callable<CalcResult> {
String taskName ;
long input1 ;
int input2 ;
CallableTask(String name , long v1 , int v2 ) {
taskName = name;
input1 = v1;
input2 = v2 ;
}
public CalcResult call() throws Exception {
System.out.println(" Task " + taskName + " Started -----");
for(int i=0;i<input2 ;i++) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
System.out.println(" Task " + taskName + " Interrupted !! ");
e.printStackTrace();
}
input1 += i;
}
System.out.println(" Task " + taskName + " Completed ######");
return new CalcResult(input1) ;
}
}
public void test(){
ExecutorService taskExecutor = Executors.newFixedThreadPool(3);
CompletionService<CalcResult> taskCompletionService = new ExecutorCompletionService<CalcResult>(taskExecutor);
int submittedTasks = 5;
for (int i=0;i< submittedTasks;i++) {
taskCompletionService.submit(new CallableTask (
String.valueOf(i),
(i * 10),
((i * 10) + 10 )
));
System.out.println("Task " + String.valueOf(i) + "subitted");
}
for (int tasksHandled=0;tasksHandled<submittedTasks;tasksHandled++) {
try {
System.out.println("trying to take from Completion service");
Future<CalcResult> result = taskCompletionService.take();
System.out.println("result for a task availble in queue.Trying to get()");
// above call blocks till atleast one task is completed and results availble for it
// but we dont have to worry which one
// process the result here by doing result.get()
CalcResult l = result.get();
System.out.println("Task " + String.valueOf(tasksHandled) + "Completed - results obtained : " + String.valueOf(l.result));
} catch (InterruptedException e) {
// Something went wrong with a task submitted
System.out.println("Error Interrupted exception");
e.printStackTrace();
} catch (ExecutionException e) {
// Something went wrong with the result
e.printStackTrace();
System.out.println("Error get() threw exception");
}
}
}
}
Basically you use a CompletionService if you want to execute multiple tasks in parallel and then work with them in their completion order. So, if I execute 5 jobs, the CompletionService will give me the first one that that finishes. The example where there is only a single task confers no extra value over an Executor apart from the ability to submit a Callable.
I think the javadoc best answers the question of when the CompletionService is useful in a way an ExecutorService isn't.
A service that decouples the production of new asynchronous tasks from the consumption of the results of completed tasks.
Basically, this interface allows a program to have producers which create and submit tasks (and even examine the results of those submissions) without knowing about any other consumers of the results of those tasks. Meanwhile, consumers which are aware of the CompletionService could poll for or take results without being aware of the producers submitting the tasks.
For the record, and I could be wrong because it is rather late, but I am fairly certain that the sample code in that blog post causes a memory leak. Without an active consumer taking results out of the ExecutorCompletionService's internal queue, I'm not sure how the blogger expected that queue to drain.
First of all, if we do not want to waste processor time, we will not use
while (!future.isDone()) {
// Do some work...
}
We must use
service.shutdown();
service.awaitTermination(14, TimeUnit.DAYS);
The bad thing about this code is that it will shut down ExecutorService. If we want to continue work with it (i.e. we have some recursicve task creation), we have two alternatives: invokeAll or ExecutorService.
invokeAll will wait untill all tasks will be complete. ExecutorService grants us ability to take or poll results one by one.
And, finily, recursive example:
ExecutorService executorService = Executors.newFixedThreadPool(THREAD_NUMBER);
ExecutorCompletionService<String> completionService = new ExecutorCompletionService<String>(executorService);
while (Tasks.size() > 0) {
for (final Task task : Tasks) {
completionService.submit(new Callable<String>() {
#Override
public String call() throws Exception {
return DoTask(task);
}
});
}
try {
int taskNum = Tasks.size();
Tasks.clear();
for (int i = 0; i < taskNum; ++i) {
Result result = completionService.take().get();
if (result != null)
Tasks.add(result.toTask());
}
} catch (InterruptedException e) {
// error :(
} catch (ExecutionException e) {
// error :(
}
}
See it by yourself at run time,try to implement both solutions (Executorservice and Completionservice) and you'll see how different they behave and it will be more clear on when to use one or the other.
There is an example here if you want http://rdafbn.blogspot.co.uk/2013/01/executorservice-vs-completionservice-vs.html
Let's say you have 5 long running task(callable task) and you have submitted those task to executer service. Now imagine you don't want to wait for all 5 task to compete instead you want to do some sort of processing on these task if any one completes. Now this can be done either by writing polling logic on future objects or use this API.
package com.barcap.test.test00;
import java.util.concurrent.*;
/**
* Created by Sony on 25-04-2019.
*/
public class ExecutorCompletest00 {
public static void main(String[] args) {
ExecutorService exc= Executors.newFixedThreadPool( 10 );
ExecutorCompletionService executorCompletionService= new ExecutorCompletionService( exc );
for (int i=1;i<10;i++){
Task00 task00= new Task00( i );
executorCompletionService.submit( task00 );
}
for (int i=1;i<20;i++){
try {
Future<Integer> future= (Future <Integer>) executorCompletionService.take();
Integer inttest=future.get();
System.out.println(" the result of completion service is "+inttest);
break;
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
=======================================================
package com.barcap.test.test00;
import java.util.*;
import java.util.concurrent.*;
/**
* Created by Sony on 25-04-2019.
*/
public class ExecutorServ00 {
public static void main(String[] args) {
ExecutorService executorService=Executors.newFixedThreadPool( 9 );
List<Future> futList= new ArrayList <>( );
for (int i=1;i<10;i++) {
Future result= executorService.submit( new Task00( i ) );
futList.add( result );
}
for (Future<Integer> futureEach :futList ){
try {
Integer inm= futureEach.get();
System.out.println("the result of future executorservice is "+inm);
break;
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
===========================================================
package com.barcap.test.test00;
import java.util.concurrent.*;
/**
* Created by Sony on 25-04-2019.
*/
public class Task00 implements Callable<Integer> {
int i;
public Task00(int i) {
this.i = i;
}
#Override
public Integer call() throws Exception {
System.out.println(" the current thread is "+Thread.currentThread().getName() +" the result should be "+i);
int sleepforsec=100000/i;
Thread.sleep( sleepforsec );
System.out.println(" the task complted for "+Thread.currentThread().getName() +" the result should be "+i);
return i;
}
}
======================================================================
difference of logs for executor completion service:
the current thread is pool-1-thread-1 the result should be 1
the current thread is pool-1-thread-2 the result should be 2
the current thread is pool-1-thread-3 the result should be 3
the current thread is pool-1-thread-4 the result should be 4
the current thread is pool-1-thread-6 the result should be 6
the current thread is pool-1-thread-5 the result should be 5
the current thread is pool-1-thread-7 the result should be 7
the current thread is pool-1-thread-9 the result should be 9
the current thread is pool-1-thread-8 the result should be 8
the task complted for pool-1-thread-9 the result should be 9
teh result is 9
the task complted for pool-1-thread-8 the result should be 8
the task complted for pool-1-thread-7 the result should be 7
the task complted for pool-1-thread-6 the result should be 6
the task complted for pool-1-thread-5 the result should be 5
the task complted for pool-1-thread-4 the result should be 4
the task complted for pool-1-thread-3 the result should be 3
the task complted for pool-1-thread-2 the result should be 2
the current thread is pool-1-thread-1 the result should be 1
the current thread is pool-1-thread-3 the result should be 3
the current thread is pool-1-thread-2 the result should be 2
the current thread is pool-1-thread-5 the result should be 5
the current thread is pool-1-thread-4 the result should be 4
the current thread is pool-1-thread-6 the result should be 6
the current thread is pool-1-thread-7 the result should be 7
the current thread is pool-1-thread-8 the result should be 8
the current thread is pool-1-thread-9 the result should be 9
the task complted for pool-1-thread-9 the result should be 9
the task complted for pool-1-thread-8 the result should be 8
the task complted for pool-1-thread-7 the result should be 7
the task complted for pool-1-thread-6 the result should be 6
the task complted for pool-1-thread-5 the result should be 5
the task complted for pool-1-thread-4 the result should be 4
the task complted for pool-1-thread-3 the result should be 3
the task complted for pool-1-thread-2 the result should be 2
the task complted for pool-1-thread-1 the result should be 1
the result of future is 1
=======================================================
for executorservice the result will only be avialable after all tasks complted.
executor completionservice any result avilable make that return.
If the task producer is not interested in the results and it is another component's responsibility to process results of asynchronous task executed by executor service, then you should use CompletionService. It helps you in separating task result processor from task producer. See example http://www.zoftino.com/java-concurrency-executors-framework-tutorial
there is another advantage of using completionservice: Performance
when you call future.get(), you are spin waiting:
from java.util.concurrent.CompletableFuture
private Object waitingGet(boolean interruptible) {
Signaller q = null;
boolean queued = false;
int spins = -1;
Object r;
while ((r = result) == null) {
if (spins < 0)
spins = (Runtime.getRuntime().availableProcessors() > 1) ?
1 << 8 : 0; // Use brief spin-wait on multiprocessors
else if (spins > 0) {
if (ThreadLocalRandom.nextSecondarySeed() >= 0)
--spins;
}
when you have a long-running task, this will be a disaster for performance.
with completionservice, once the task is done, it's result will be enqueued and you can poll the queue with lower performance overhand.
completionservice achieve this by using wrap task with a done hook.
java.util.concurrent.ExecutorCompletionService
private class QueueingFuture extends FutureTask<Void> {
QueueingFuture(RunnableFuture<V> task) {
super(task, null);
this.task = task;
}
protected void done() { completionQueue.add(task); }
private final Future<V> task;
}
assuming you execute a tasks in parallel and you save the Future results in a list:
The practical main difference between ExecutorService and CompletionService is:
ExecutorService get() will try to retrieve the results in the submitted order waiting for completion.
CompletionService take() + get() will try to retrieve the results in the completion order disregarding the submission order.
ExecutorCompletionService class implements CompletionService.
ExecutorCompletionService returns futures objects based on completion order, so whichever task executes first, will be returned first. You just need to call executorCompletionService.take() to get completed Future object.
I found a blog that clear my thought.
java2blog link with example

Under what conditions will BlockingQueue.take throw interrupted exception?

Let us suppose that I have a thread that consumes items produced by another thread. Its run method is as follows, with inQueue being a BlockingQueue
boolean shutdown = false;
while (!shutdown) {
try {
WorkItem w = inQueue.take();
w.consume();
} catch (InterruptedException e) {
shutdown = true;
}
}
Furthermore, a different thread will signal that there are no more work items by interrupting this running thread. Will take() throw an interrupted exception if it does not need to block to retrieve the next work item. i.e. if the producer signals that it is done filling the work queue, is it possible to accidentally leave some items in inQueue or miss the interrupt?
A good way to signal termination of a blocking queue is to submit a 'poison' value into the queue that indicates a shutdown has occurred. This ensures that the expected behavior of the queue is honored. Calling Thread.interupt() is probably not a good idea if you care about clearing the queue.
To provide some code:
boolean shutdown = false;
while (!shutdown) {
try {
WorkItem w = inQueue.take();
if (w == QUEUE_IS_DEAD)
shutdown = true;
else
w.consume();
} catch (InterruptedException e) {
// possibly submit QUEUE_IS_DEAD to the queue
}
}
I wondered about the same thing and reading the javadoc for take() I believed that it would throw an interrupted exception only after having taken all the items in the queue, since if the queue had items, it would not have to "wait".
But I made a small test:
package se.fkykko.slask;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicLong;
public class BlockingQueueTakeTest {
public static void main(String[] args) throws Exception {
Runner t = new Runner();
Thread t1 = new Thread(t);
for (int i = 0; i < 50; i++) {
t.queue.add(i);
}
System.out.println(("Number of items in queue: " + t.queue.size()));
t1.start();
Thread.sleep(1000);
t1.interrupt();
t1.join();
System.out.println(("Number of items in queue: " + t.queue.size()));
System.out.println(("Joined t1. Finished"));
}
private static final class Runner implements Runnable {
BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(100);
AtomicLong m_count = new AtomicLong(0);
#Override
public void run() {
try {
while (true) {
queue.take();
System.out.println("Took item " + m_count.incrementAndGet());
final long start = System.currentTimeMillis();
while ((System.currentTimeMillis() - start) < 100) {
Thread.yield(); //Spin wait
}
}
}
catch (InterruptedException ex) {
System.out.println("Interrupted. Count: " + m_count.get());
}
}
}
}
The runner will take 10-11 items and then finish i.e. take() will throw InterruptedException even if there still is items in the queue.
Summary: Use the Poison pill approach instead, then you have full control over how much is left in the queue.
According to javadoc, the take() method will throw InterruptedException if interrupted while waiting.
You can't in general interrupt the threads of an ExecutorService from external code if you used ExecutorService::execute(Runnable) to start the threads, because external code does not have a reference to the Thread objects of each of the running threads (see the end of this answer for a solution though, if you need ExecutorService::execute). However, if you instead use ExecutorService::submit(Callable<T>) to submit the jobs, you get back a Future<T>, which internally keeps a reference to the running thread once Callable::call() begins execution. This thread can be interrupted by calling Future::cancel(true). Any code within (or called by) the Callable that checks the current thread's interrupt status can therefore be interrupted via the Future reference. This includes BlockingQueue::take(), which, even when blocked, will respond to thread interruption. (JRE blocking methods will typically wake up if interrupted while blocked, realize they have been interrupted, and throw an InterruptedException.)
To summarize: Future::cancel() and Future::cancel(true) both cancel future work, while Future::cancel(true) also interrupts ongoing work (as long as the ongoing work responds to thread interrupt). Neither of the two cancel invocations affects work that has already successfully completed.
Note that once a thread is interrupted by cancellation, an InterruptException will be thrown within the thread (e.g. by BlockingQueue::take() in this case). However, you a CancellationException will be thrown back in the main thread the next time you call Future::get() on a successfully cancelled Future (i.e. a Future that was cancelled before it completed). This is different from what you would normally expect: if a non-cancelled Callable throws InterruptedException, the next call to Future::get() will throw InterruptedException, but if a cancelled Callable throws InterruptedException, the next call to Future::get() will through CancellationException.
Here's an example that illustrates this:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
public class Test {
public static void main(String[] args) throws Exception {
// Start Executor with 4 threads
int numThreads = 4;
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(numThreads);
try {
// Set up BlockingQueue for inputs, and List<Future> for outputs
BlockingQueue<Integer> queue = new LinkedBlockingQueue<Integer>();
List<Future<String>> futures = new ArrayList<>(numThreads);
for (int i = 0; i < numThreads; i++) {
int threadIdx = i;
futures.add(executor.submit(new Callable<String>() {
#Override
public String call() throws Exception {
try {
// Get an input from the queue (blocking)
int val = queue.take();
return "Thread " + threadIdx + " got value " + val;
} catch (InterruptedException e) {
// Thrown once Future::cancel(true) is called
System.out.println("Thread " + threadIdx + " got interrupted");
// This value is returned to the Future, but can never
// be read, since the caller will get a CancellationException
return "Thread " + threadIdx + " got no value";
}
}
}));
}
// Enqueue (numThreads - 1) values into the queue, so that one thread blocks
for (int i = 0; i < numThreads - 1; i++) {
queue.add(100 + i);
}
// Cancel all futures
for (int i = 0; i < futures.size(); i++) {
Future<String> future = futures.get(i);
// Cancel the Future -- this doesn't throw an exception until
// the get() method is called
future.cancel(/* mayInterruptIfRunning = */ true);
try {
System.out.println(future.get());
} catch (CancellationException e) {
System.out.println("Future " + i + " was cancelled");
}
}
} finally {
// Terminate main after all threads have shut down (this call does not block,
// so main will exit before the threads stop running)
executor.shutdown();
}
}
}
Each time you run this, the output will be different, but here's one run:
Future 1 was cancelled
Future 0 was cancelled
Thread 2 got value 100
Thread 3 got value 101
Thread 1 got interrupted
This shows that Thread 2 and Thread 3 completed before Future::cancel() was called. Thread 1 was cancelled, so internally InterruptedException was thrown, and externally CancellationException was thrown. Thread 0 was cancelled before it started running. (Note that the thread indices won't in general correlate with the Future indices, so Future 0 was cancelled could correspond to either thread 0 or thread 1 being cancelled, and the same for Future 1 was cancelled.)
Advanced: one way to achieve the same effect with Executor::execute (which does not return a Future reference) rather than Executor::submit would be to create a ThreadPoolExecutor with a custom ThreadFactory, and have your ThreadFactory record a reference in a concurrent collection (e.g. a concurrent queue) for every thread created. Then to cancel all threads, you can simply call Thread::interrupt() on all previously-created threads. However, you will need to deal with the race condition that new threads may be created while you are interrupting existing threads. To handle this, set an AtomicBoolean flag, visible to the ThreadFactory, that tells it not to create any more threads, then once that is set, cancel the existing threads.
The java.concurrency.utils package was designed and implemented by some of the finest minds in concurrent programming. Also, interrupting threads as a means to terminate them is explicitly endorsed by their book "Java Concurrency in Practice". Therefore, I would be extremely surprised if any items were left in the queue due to an interrupt.

Categories

Resources