Does threads of ThreadPoolExecutor not runs concurrently using with PriorityBlockingQueue - java

I am using java ThreadPoolExecutor to run concurrent thread execution. I used ArrayBlockingQueue to keep threads in queue. But now requirement has changed and I need to add thread run time(no size limit) and it should be prioritized.
So i decided to use PriorityBlockingQueue instead of ArrayBlockingQueue with some comparison Logic.
After using PriorityBlockingQueue, threads are running sequentially one after one not concurrently. Only one thread run at a time, rather than whatever the active thread count will be.
Please let me know if anybody have any suggestions to resolve this issue and achieve my requirement(thread should be added in pool at run time and it execution should be based on priority).
My demo code:
//RejectedExecutionHandler implementation
RejectedExecutionHandlerImpl rejectionHandler = new RejectedExecutionHandlerImpl();
//Get the ThreadFactory implementation to use
BlockingQueue<Runnable> queue = new PriorityBlockingQueue<Runnable>(50, ThreadComparator.getComparator());
ThreadPoolExecutor executorPool = new ThreadPoolExecutor(1, activeThread, 10, TimeUnit.SECONDS, queue, threadFactory, rejectionHandler);
//start the monitoring thread
MyMonitorThread monitor = new MyMonitorThread(executorPool, 20, "Demo");
Thread monitorThread = new Thread(monitor);
monitorThread.start();
for (int i = 0; i < totalThead; i++) {
int prio = i % 3 == 0 ? 3 : 5;
executorPool.execute(new MyThread("Thread-" + i, prio));
}
// Inserting more threads in between concurrent execution.
try {
Thread.sleep(40000);
for (int j = 101; j < 110; j++) {
executorPool.execute(new MyThread("Thread-" + j, 2));
}
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
while(executorPool.getActiveCount() != 0) {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("Error while thread sleeping: " + e);
}
}
//shut down the pool
executorPool.shutdown();
//shut down the monitor thread
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
System.out.println("Error while thread sleeping: " + e);
}
monitor.shutdown();
public abstract class ThreadComparator implements Comparator<Runnable>{
public static Comparator<Runnable> getComparator() {
return new Comparator<Runnable>() {
#Override
public int compare(Runnable t1, Runnable t2) {
CompareToBuilder compare = new CompareToBuilder();
MyThread mt1 = (MyThread) t1;
MyThread mt2 = (MyThread) t2;
compare.append(mt1.getPriority(), mt2.getPriority());
return compare.toComparison();
}
};
}
}

This is the expected behaviour of ThreadPoolExecutor with an unbounded work queue.
To cite the ThreadPoolExecutor JavaDoc:
Core and maximum pool sizes
A ThreadPoolExecutor will automatically adjust the pool size [..].
When a new task is submitted in method execute(Runnable), and fewer
than corePoolSize threads are running, a new thread is created to
handle the request, even if other worker threads are idle. If there
are more than corePoolSize but less than maximumPoolSize threads
running, a new thread will be created only if the queue is full. [...]
Since you define corePoolSize as 1 and a PriorityBlockingQueue is essentially an unbounded queue (that can never become full), you will never have more than one thread.
The fix is to adjust the corePoolSize to the required number of threads.

Related

Java one producer and two consumers

I have a producer and two consumers. I want to display how the consumers take the values from producer and displayed them.
The problem is that in my code only the second consumer displayed the item from producer.
How to solve this?
here is the problem:
public static void main(String[] args) throws Exception {
// Object of a class that has both produce()
// and consume() methods
final ProdConsumer pc = new ProdConsumer();
// Create producer thread
Thread t1 = new Thread(new Runnable() {
public void run() {
try {
pc.produce();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// Create consumer thread
Thread t2 = new Thread(new Runnable() {
public void run() {
try {
pc.consume(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread t3 = new Thread(new Runnable() {
public void run() {
try {
pc.consume(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// Start both threads
t1.start();
t2.start();
t3.start();
// // t1 finishes before t2
t1.join();
t2.join();
t3.join();
}
And producer_consumer class:
public class ProdCons
{
// Create a list shared by producer and consumer
// Size of list is 2.
LinkedList<Integer> list = new LinkedList<Integer>();
int capacity = 2;
// Function called by producer thread
public void produce() throws InterruptedException
{
int value = 0;
while (true)
{
synchronized (this)
{
// producer thread waits while list
// is full
while (list.size()==capacity)
wait();
System.out.println("Producer produced-"
+ value);
// to insert the jobs in the list
list.add(value++);
// notifies the consumer thread that
// now it can start consuming
notify();
// makes the working of program easier
// to understand
Thread.sleep(1000);
}
}
}
// Function called by consumer thread
public void consume(int thread) throws InterruptedException
{
while (true)
{
synchronized (this)
{
// consumer thread waits while list
// is empty
while (list.size()==0)
wait();
//to retrive the ifrst job in the list
int val = list.removeFirst();
System.out.println("Consumer" + thread + " consumed-"
+ val);
// Wake up producer thread
notify();
// and sleep
Thread.sleep(1000);
}
}
}
}
Thank you
What am I missing?
wait/notify mechanism isn't fair, that means that if there are two threads waiting for the same resource, any of them could be notified when you call notify(). That sometimes is an issue of starvation problem.
So in your case when you are notifying first time, for example, first consumer gets this notification, and then after finishing his job it calls wait again, that means that on second time producer calls notify you have again two consumers waiting and then there is no guarantee that it would wake up another consumer, it could be any of them.
This problem will go away in case you will decrease Thread.sleep amount in producer, to be less than in consumer. Actually may be its not even a problem, because in your case throughput of consumer is the same as in producer, so basically you don't need second consumer, however its a rare case in real life, so to emulate the case when you have both consumers working, you should increase throughput of the producer.
However in my opinion you should really think before using such low level mechanism as wait/notify. Take a look at BlockingQueue, for example, or other concurrency primitives in java. For example you can make ArrayBlockingQueue to be fair:
Java doc: This class supports an optional fairness policy for ordering waiting producer and consumer threads. By default, this ordering is not guaranteed. However, a queue constructed with fairness set to true grants threads access in FIFO order. Fairness generally decreases throughput but reduces variability and avoids starvation.
So instead of list you will have this queue, and when calling take on this queue you will either get next element in a queue to consume or, in case its empty, your thread will block until there will be new elements.
And specifying fair flag to be true means that it will use FIFO for next consumer to wake up.
So your code will look like:
public class ProdCons {
// Create a queue shared by producer and consumer
// Size of list is 2.
BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(2, true);
int capacity = 2;
// Function called by producer thread
public void produce() throws InterruptedException {
int value = 0;
while (true) {
System.out.println("Producer produced-" + value);
// to insert the jobs in the queue
// will block in case there is no more space in a queue
queue.put(value++);
// and sleep
Thread.sleep(500);
}
}
// Function called by consumer thread
public void consume(int thread) throws InterruptedException {
while (true) {
//retrieve the first job in the queue
//will block in case queue is empty, until its not empty
int val = queue.take();
System.out.println("Consumer" + thread + " consumed-"
+ val);
// and sleep
Thread.sleep(1000);
}
}
}
Also you may be interesting in this article explaining starvation and wait/notify fairness: http://tutorials.jenkov.com/java-concurrency/starvation-and-fairness.html
To illustrate my comment on the not using wait/notify, here's a producer/consumer with a BlockingQueue. Sorry if that doesn't actually answer your question about why the code doesn't work.
static final AtomicInteger value = new AtomicInteger();
public static void main(String[] args) {
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(2);
Thread producer = new Thread(() -> { queue.put(value.getAndIncrement()) });
producer.start();
Runnable consumer1 = () -> {
try {
while(true) {
System.out.println("Consumer 1 consuming " + queue.take());
Thread.sleep(200);
}
}{ catch(Exception e) {}
};
Runnable consumer2 = () -> {
try {
while(true) {
System.out.println("Consumer 2 consuming " + queue.take());
Thread.sleep(200);
}
}{ catch(Exception e) {}
};
new Thread(consumer1).start();
new Thread(consumer2).start();
}
Side note, I usually wouldn't even create Thread objects directly but use an ExecutorService instead, but that's beside the point.
I would like to solve this problem in different way using java message queue(JMS) by publish and subscribe. The publish/subscribe messaging domain is a one-to-many model where one publisher sends the message through a topic to all the subscribers who are active and they receive the message through topic. it is simple and easy to implement. here is the details.
https://howtodoinjava.com/jms/jms-java-message-service-tutorial/
The t1.join t2.join t3.join will only let the main thread wait for the t1,t2,t3 producer and consumer threads to finish. In this case all threads run in while loop so join call doesn't make any difference. Also, a thread does not get to wait, if the synchronized block in that thread is not executed. Depending on who acquire the lock first, the synchronized blocks , will get executed.
First of all, you need to use .notifyAll(), not .notify() (which can be bad if one consumer notifies the other consumer; the producer would never wake).
Second, the data isn't sent to 2 lists but only one and the consumers are fighting to get from the same place; java has always said that there is no predictable thread scheduling under such case like sleep/wait/synchonized etc... Having only one consumer and the same repeatedly waking is within spec.
You need to use ReentrantLock(true) for a fair locking/waking.
Each of your threads is synchronized on itself (this), which will be different for each thread, so it won't prevent them from operating at the same time. Since they're (supposed to be) manipulating a list shared across the threads, they should probably synchronize on that list (or some other shared lock object). And, more problematically, it looks like each thread creates its own List - they won't share lists. The List should either be a static (class) list, or it should be passed in to each thread.

ThreadPoolExecutor not shrinking at low load

In my program most of the time tasks are rarely submitted to the executor, yet they don't cease completely. There are periodic bursts when many tasks are submitted at once.
Even though allowCoreThreadTimeOut is set and only one thread would be enough most of the time, the redundant executor threads don't stop.
This is because of the fairness of the executor's blocking queue: when multiple threads wait for it, all have equal chance to get a task and their idle time doesn't grow significantly.
Is there a workaround? For example, a queue that in case of multiple waiting threads returns in the thread with lowest id?
public class ShrinkTPE {
public static void main(final String[] args) throws Exception {
final ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors
.newFixedThreadPool(NTHREADS);
executor.setKeepAliveTime(ALIVE_TIME, TimeUnit.SECONDS);
executor.allowCoreThreadTimeOut(true);
// thread alive time is 10s
// load all threads with tasks at start and every 12s
// also submit one task each second
for (int i = 0;; i++) {
int j = 0;
do {
if (false && !mostThreadsUnused(i))
break;
final int i2 = i, j2 = j;
executor.submit(new Callable<Void>() {
#Override
public Void call() throws Exception {
System.out.println(""
+ Thread.currentThread().getName() + " " + i2
+ " " + j2);
Thread.sleep(300);
return null;
}
});
} while (mostThreadsUnused(i) && ++j < NTHREADS);
Thread.sleep(1000);
System.out.println();
}
}
private static boolean mostThreadsUnused(final int i) {
return i % (ALIVE_TIME + 2) == 0;
}
private static final int NTHREADS = 5;
private static final int ALIVE_TIME = 10;
}
final ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(N_THREAD);
You are using fixedThreadPool and that means, that pool will have N_THREAD number of threads constantly all the time. allowCoreThreadTimeout is neglected here.
Use different thread pool, perhaps CachedThreadPool? It will reuse existing threads, but it will spin up additional threads if you submit new task to the pool and there will be no idle thread.
Idle threads dies after X amount of time (default 60 seconds of idle)
The official JDK implementation of newCachedThreadPool is as follows. You can simply call that constructor directly if you want to set a maximum thread pool size or customized the keepAliveTime or use a different queue.
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}

Best Queue Consumer implementation in Java

Good day!
I want to make an ExecutorService consumers for taking data from queue and working with it on server side. The idea is - I poll queue from time to time and if I see that it is not empty I start ExecutorService with N threads (lets say 5). Then I w8 while queue will be empty and shutdown threads. And all again - poll queue for data....
Is this alg ok? Or may be there are some ready implementations/frameworks for such task?
I found this implementation of ConcurrentQueue cunsumers :
public class ConcurrentQueueClient implements Runnable {
private Queue<String> concurrentQueue;
public ConcurrentQueueClient(Queue concurrentQueue) {
this.concurrentQueue = concurrentQueue;
}
public void run() {
boolean stopCondition = (concurrentQueue.size() == 0);
while (!stopCondition) {
for (int i = 0; i < concurrentQueue.size(); i++) {
System.out.println("Client dequeue item "
+ concurrentQueue.poll());
}
stopCondition = (concurrentQueue.size() == 0);
}
System.out.println("Client thread exiting...");
}
}
and testing it in such way :
Queue<String> queue = new ConcurrentLinkedQueue<String>();
ExecutorService consumers = null;
while(true) {
if(queue.size() != 0) {
consumers = Executors.newFixedThreadPool(100);
for (int i = 0; i < 5; i++) {
ConcurrentQueueClient client = new ConcurrentQueueClient(queue);
consumers.execute(client);
}
}
while (queue.size() != 0) {
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
consumers.shutdown();
try {
consumers.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Start over.
Wrap your strings in callable or runnable, and queue those to the executor service.
If you have a finite set of data to process, then it's ok to have the main thread calling consumer.shutdown() and consumer.awaitTermination(...) as before, but no sleep loop. If you are going to process indefinitely from the queue, then no shutdown() until the service is.
You will face memory issues too if you don't have a limited blocking queue (nothing to block queue.put()). An ArrayBlockingQueue can be given to the executor service on creation (see ThreadPoolExecutor(...) )
Executor service's threads are doing that check (queue.take()) of the tasks queue by design. Try to avoid polling, it waste CPU. Always try to wait/notify (or await/signal) on conditions from reentrantlocks (which is all taken care of for you in the executor service code)

What are core threads in a ThreadPoolExecutor?

I was looking at the ThreadPoolExecutor class and I found that it allows to specify the maximum pool size and the core pool size.
I understand, a little, about when to change the core and maximum pool sizes based on the answer here: When is specifying separate core and maximum pool sizes in ThreadPoolExecutor a good idea?
However, I would like to know what are these 'core threads'. I always get 0 when I use the getCorePoolSize() method of a ThreadPoolExecutor
SSCCE here:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
public class PoolSize {
public static void main(String[] args) {
// Create a cached thread pool
ExecutorService cachedPool = Executors.newCachedThreadPool();
// Cast the object to its class type
ThreadPoolExecutor pool = (ThreadPoolExecutor) cachedPool;
// Create a Callable object of anonymous class
Callable<String> aCallable = new Callable<String>(){
String result = "Callable done !";
#Override
public String call() throws Exception {
// Print a value
System.out.println("Callable at work !");
// Sleep for 5 sec
Thread.sleep(0);
return result;
}
};
// Create a Runnable object of anonymous class
Runnable aRunnable = new Runnable(){
#Override
public void run() {
try {
// Print a value
System.out.println("Runnable at work !");
// Sleep for 5 sec
Thread.sleep(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
// Submit the two tasks for execution
Future<String> callableFuture = cachedPool.submit(aCallable);
Future<?> runnableFuture = cachedPool.submit(aRunnable);
System.out.println("Core threads: " + pool.getCorePoolSize());
System.out.println("Largest number of simultaneous executions: "
+ pool.getLargestPoolSize());
System.out.println("Maximum number of allowed threads: "
+ pool.getMaximumPoolSize());
System.out.println("Current threads in the pool: "
+ pool.getPoolSize());
System.out.println("Currently executing threads: "
+ pool.getTaskCount());
pool.shutdown(); // shut down
}
}
core threads is the minimum which is always running just in case you want to pass it a task. The cached pool by default has a core of 0 as you might expect.
For the fixed thread pool, the core and the maximum are the same i.e. whatever you set the fixed size to.
The core threads are just standard threads but will be always kept alive in the pool, and then the other non-core threads will end their lives after the run() method finished.
But how could these core threads be always alive? That's because they are always waiting for taking a task from the workQueue shared within the pool. By default, the workQueue is a BlockingQueue, its take() method will block the current thread indefinitely until a task becomes available.
Here comes the key point, which threads will become the core threads? They may not be the first started ones or the last ones, but the ones(corePoolSize) that last the longest. Easier to understand from the code.
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
//------------- key code ------------------
// Are workers subject to culling?
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
//------------- key code ------------------
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
What I just said above is based on allowCoreThreadTimeOut set as false.
Actually, I prefer to call core threads as core workers.

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