I am trying to create various singleton patterns and check for breaks using millions of threads. I was hoping this would lead me to implement Bill Pugh ultimately. But I am not even able to break the classical one.
Singleton: Previously tried a million threads, all were having same hashcode. So I made it sleep for 10 sec so that both threads are sure to enter null check condition but all in frustration.
package demo2;
public class Singleton {
private static Singleton soleInstance = null;
private Singleton() throws InterruptedException {
}
public static Singleton getInstance() throws InterruptedException {
if (soleInstance == null) {
Thread.sleep(10000);
soleInstance = new Singleton();
}
return soleInstance;
}
}
Test Class:
package demo2;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
class Test {
public int makeSingleton() throws InterruptedException {
Singleton s = Singleton.getInstance();
return s.hashCode();
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
Test t = new Test();
ExecutorService executor = Executors.newFixedThreadPool(2);
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 2; i++) {
Future<Integer> future = executor.submit(new Callable<Integer>() {
public Integer call() throws InterruptedException {
return t.makeSingleton();
}
});
list.add(future.get());
}
executor.shutdown();
List<Integer> list2 = list.stream().distinct().collect(Collectors.toList());
System.out.println(list2);
}
}
How the hell do I break it?
Below mentioned code will work.
Change your code. May be you are calling get inside method only and it's waiting to get results & loop count won't increment.
ExecutorService executor = Executors.newFixedThreadPool(2);
List<Future<Integer>> list = new ArrayList<Future<Integer>>();
for (int i = 0; i < 5; i++) {
Future<Integer> future = executor.submit(new Callable<Integer>() {
public Integer call() throws InterruptedException {
return Singleton.getInstance().hashCode();
}
});
list.add(future);
}
executor.shutdown();
Set<Integer> output = new HashSet<Integer>();
for(Future<Integer> future : list){
output.add(future.get());
}
System.out.println(output);
Please check this:
/**
* <p>
* If you would like to immediately block waiting
* for a task, you can use constructions of the form
* {#code result = exec.submit(aCallable).get();}
*/
<T> Future<T> submit(Callable<T> task);
If you use
Future<Integer> future = executor.submit(new Callable<Integer>()
it will block you thread till the result return.
If you want to break the classical singleton pattern, try this code
public class BreakSingleton {
public MySingleton makeSingleton() throws InterruptedException {
MySingleton s = MySingleton.getInstance();
return s;
}
public static void main(String[] args) throws Exception {
BreakSingleton t = new BreakSingleton();
ExecutorService executor = Executors.newFixedThreadPool(2);
final List<MySingleton> list = new ArrayList<>();
System.out.println(Thread.currentThread().getName());
for (int i = 0; i < 2; i++) {
executor.submit(new Callable<MySingleton>() {
public MySingleton call() throws InterruptedException {
MySingleton mySingleton = t.makeSingleton();
list.add(mySingleton);
return mySingleton;
}
});
}
executor.shutdown();
Thread.sleep(5000);
System.out.println(list);
}
}
class MySingleton {
private static MySingleton instance = null;
private MySingleton() {
}
public static MySingleton getInstance() throws InterruptedException {
System.out.println(Thread.currentThread().getName());
if (instance == null) {
Thread.sleep(3000);
System.out.println(Thread.currentThread().getName());
instance = new MySingleton();
}
return instance;
}
}
Related
I just wonder explanation of how this code is working
assume we have Work class in below
public class Work {
private static ThreadPoolExecutor executorService;
private Work(){};
public static void instansiate(int numberOfThread){
executorService= (ThreadPoolExecutor) Executors.newFixedThreadPool(numberOfThread);
}
public static void shutDown(){
executorService.shutdown();
}
public static ExecutorService getExecutorService() {
return executorService;
}
public static int getThreadCount(){
return executorService.getCorePoolSize();
}
}
and im calling this class somewhere in method like below
public static void xx() throws ExecutionException, InterruptedException {
Work.instansiate(2);
System.out.println("Thread count= " + Work.getThreadCount());
ExecutorService executorService = Work.getExecutorService();
Future<String> future1 = executorService.submit(new Callable<String>() {
#Override
public String call() throws Exception {
return "future1";
}
});
String resFuture1 = future1.get();
System.out.println(resFuture1);
Work.shutDown();
Future<String> future2 = executorService.submit(new Callable<String>() {
#Override
public String call() throws Exception {
return "future2";
}
});
String resFuture2 = future2.get();
System.out.println(resFuture2);
}
This code is throwing exception after Work.shutDown() line and says rejected from java.util.concurrent.ThreadPoolExecutor#234bef66[Terminated, pool size = 0, active threads = 0 ...
I had assigned Work.getExecutorService to another executorService how closing Work executorservice can block assigned one.
Actually executorService holding same reference with Work.executorService(), Thus it was affected of closing Work's executorservice.
I am facing a problem with a Runnable class. The value that is passed to the runnable class is overwritten by the last value it received when the same value is passed to another class.
The function of the runnable class is to pass the values to another function in another class to print them. But only the last value received by the Runnable class is printed.
Here is my code,
This is the main class from where the values are passed.
public class MainClass {
private int intVal = -1;
public void MainMethod() {
ExecutorUtil theExecutor = ExecutorUtil.GetInstance();
for(int i = 0; i < 3; i++) {
intVal = i;
synchronized (this) {
theExecutor.SubmitTask(new ActionExecutor(intVal));
}
}
}
}
This is the executorUtil that I use to call the thread.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.BlockingQueue;
public class ExecutorUtil {
private static ExecutorUtil theInstance;
private ExecutorService theExecutor;
private BlockingQueue<Runnable> theQueue;
protected ExecutorUtil() {
theExecutor = CreateThreadPoolExecutor();
}
private ExecutorService CreateThreadPoolExecutor() {
theQueue = new LinkedBlockingQueue<Runnable>();
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10, 900, java.util.concurrent.TimeUnit.SECONDS, theQueue);
threadPoolExecutor.allowCoreThreadTimeOut(true);
return threadPoolExecutor;
}
public static ExecutorUtil GetInstance() {
if (theInstance == null) {
synchronized(ExecutorUtil.class) {
if (theInstance == null) {
theInstance = new ExecutorUtil();
}
}
}
return theInstance;
}
public void SubmitTask(Runnable runnable) {
theExecutor.submit(runnable);
}
}
This is the thread that passes the received value to the function that prints these values.
public class ActionExecutor implements Runnable {
int iVal = -1;
public ActionExecutor(int iVal) {
this.iVal = iVal;
}
public void run() {
SecondClass sc = new SecondClass();
sc.printIntVal(iVal);
}
}
And this is the class that prints the values.
public class SecondClass {
public void printIntVal(int i) {
System.out.println(i);
}
}
Expected Output:
0
1
2
Obtained Output:
2
2
2
No idea why this is behaving in this way!
UPDATE:
The issue occurs only when a non-primitive data type is used. In my example here, I've used an integer value (intVal). Since java passes the value for primitive data types, the output was obtained as expected. But in my original code, I've used a JSONObject. And since java passes the reference of the object for non-primitive data types, the value was over-written.
I have solved this by creating new JSONObject for each iteration.
It seems that somewhere you have static field, which store your number.
So, I suppose, that you have 3 instances of ActionExecutor, but it looks like field has static modifier, so each of this instance will have latest value.
Check this case...
So after I read your question and studied your code I might as well try it out. And lo and behold it's working as expected. The only difference here is that there is a race condition so the output my vary in order, but it will not print the same numbers.
Output might
1st: 0 1 2
2nd: 0 1 2
3rd: 2 1 0
Here is the full code to try it out:
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
public class MainClass {
private int intVal = -1;
public void MainMethod() {
ExecutorUtil theExecutor = ExecutorUtil.GetInstance();
for(int i = 0; i < 3; i++) {
intVal = i;
synchronized (this) {
theExecutor.SubmitTask(new ActionExecutor(intVal));
}
}
}
public class ActionExecutor implements Runnable {
int iVal = -1;
public ActionExecutor(int iVal) {
this.iVal = iVal;
}
public void run() {
SecondClass sc = new SecondClass();
sc.printIntVal(iVal);
}
}
public class SecondClass {
public void printIntVal(int i) {
System.out.println(i);
}
}
public static class ExecutorUtil {
private static ExecutorUtil theInstance;
private ExecutorService theExecutor;
private BlockingQueue<Runnable> theQueue;
protected ExecutorUtil() {
theExecutor = CreateThreadPoolExecutor();
}
private ExecutorService CreateThreadPoolExecutor() {
theQueue = new LinkedBlockingQueue<Runnable>();
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10, 900, java.util.concurrent.TimeUnit.SECONDS, theQueue);
threadPoolExecutor.allowCoreThreadTimeOut(true);
return threadPoolExecutor;
}
public static ExecutorUtil GetInstance() {
if (theInstance == null) {
synchronized(ExecutorUtil.class) {
if (theInstance == null) {
theInstance = new ExecutorUtil();
}
}
}
return theInstance;
}
public void SubmitTask(Runnable runnable) {
theExecutor.submit(runnable);
}
}
public static void main(String[] args) {
MainClass main = new MainClass();
main.MainMethod();
}
}
You might want to clean and rebuild your project. Otherwise it's working..
DefaultRunners are producers
and OrderTaker is a consumer
They both share a OrderQueue.
Currently, I use the variable isDone to indicate if a game is finished.
Once each round is done, I want to make it repeat again and again.
However, in my current implementation it will only run once.
How could I solve it?
public class OrderQueue {
public synchronized void pushOrder(Order order) throws InterruptedException {
if (isDone) {
wait();
} else {
runnersQueue.addLast(order);
notifyAll();
}
}
public void pullOrder() {
try {
if (runnersQueue.size() == 0) {
} else if (isDone) {
wait();
} else {
handleOrder(runnersQueue.pop());
}
} catch (InterruptedException e) {
}
}
In my main class
while(true){
enterYesToStart();
DefaultRunners dfltRunner = new DefaultRunners(queue);
OrderTaker taker = new OrderTaker(queue);
taker.run();
System.out.println("This round is finished"); # never reach to this line
}
Here's the full source code for the example
https://gist.github.com/poc7667/d98e3bf5b3b470fcb51e00d9a0d80931
I've taken a look at your code snippets and the problem is fairly obvious.
The main thread runs the OrderTaker runnable. The main thread is stuck in an eternal loop as the while statement cannot complete unless it throws an exception. (Note that the same is true for your ThreadRunner runnable.)
This means that the main thread i still pulling orders while the race is already done.
The OrderTaker should exit it's while loop while once the race is done. I guess that there are multiple ways achieve this, but one way is use a shared variable.
I took your code and adapted it into a working example.
import java.util.*;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class RaceApp {
public static void main(String[] args) throws InterruptedException {
final RaceUpdateManager queue = new RaceUpdateManager();
for (int i = 0; i < 3; i++) {
queue.reset();
List<Thread> threads = Arrays.asList(
new Thread(new Runner("Tortoise", 0, 10, queue)),
new Thread(new Runner("Hare", 90, 100, queue))
);
for (Thread thread : threads) {
thread.start();
}
RaceUpdatesProcessor processor = new RaceUpdatesProcessor(queue);
processor.run();
System.out.println("Game finished");
}
}
private static class RaceUpdateManager {
private static final int TOTAL_DISTANCE = 300;
//thread-safe implementation for queue so no external syncrhonization is required when adding/removing updates
private final Deque<RaceUpdate> runnersQueue = new ConcurrentLinkedDeque<>();
//lock used to sync changes to runnersRecords and done variables
private final ReadWriteLock raceStatusLock = new ReentrantReadWriteLock();
private final Map<String, Integer> runnersRecords = new HashMap<>();
private volatile boolean raceDone = false;//volatile keyword guarantees visibility of changes to variables across threads
public boolean isRaceDone() {
return raceDone;
}
//updates can by added simultaneously (read lock)
public void register(RaceUpdate raceUpdate) throws InterruptedException {
Lock readLock = raceStatusLock.readLock();
readLock.lock();
try {
if (!raceDone) {
runnersQueue.addLast(raceUpdate);
}//ignore updates when the race is done
} finally {
readLock.unlock();
}
}
//but they need to be processed in order (exclusive write lock)
public void processOldestUpdate() {
Lock writeLock = raceStatusLock.writeLock();
writeLock.lock();
try {
RaceUpdate raceUpdate = runnersQueue.poll();
if (raceUpdate != null) {
handleUpdate(raceUpdate);
}
} finally {
writeLock.unlock();
}
}
private void handleUpdate(RaceUpdate raceUpdate) {
Integer distanceRun = runnersRecords.merge(
raceUpdate.runner, raceUpdate.distanceRunSinceLastUpdate, (total, increment) -> total + increment
);
System.out.printf("%s: %d\n", raceUpdate.runner, distanceRun);
if (distanceRun >= TOTAL_DISTANCE) {
raceDone = true;
System.out.printf("Winner %s\n", raceUpdate.runner);
}
}
public void reset() {
Lock writeLock = raceStatusLock.writeLock();
writeLock.lock();
try {
runnersQueue.clear();
runnersRecords.clear();
raceDone = false;
} finally {
writeLock.unlock();
}
}
}
public static class Runner implements Runnable {
private final String name;
private final int rest;
private final int speed;
private final RaceUpdateManager queue;
private final Random rand = new Random();
public Runner(String name, int rest, int speed, RaceUpdateManager queue) {
this.name = name;
this.rest = rest;
this.speed = speed;
this.queue = queue;
}
#Override
public void run() {
while (!queue.isRaceDone()) {
try {
if (!takeRest()) {
queue.register(new RaceUpdate(this.name, this.speed));
}
Thread.sleep(100);
} catch (InterruptedException e) {
//signal that thread was interrupted and exit method
Thread.currentThread().interrupt();
return;
}
}
}
private boolean takeRest() {
return rand.nextInt(100) < rest;
}
}
public static class RaceUpdatesProcessor implements Runnable {
private final RaceUpdateManager queue;
public RaceUpdatesProcessor(RaceUpdateManager queue) {
this.queue = queue;
}
#Override
public void run() {
while (!queue.isRaceDone()) {
try {
queue.processOldestUpdate();
Thread.sleep(50);
} catch (InterruptedException e) {
//signal that thread was interrupted and exit method
Thread.currentThread().interrupt();
return;
}
}
}
}
public static class RaceUpdate {
public final String runner;
public final int distanceRunSinceLastUpdate;
public RaceUpdate(String runner, int distanceRunSinceLastUpdate) {
this.runner = runner;
this.distanceRunSinceLastUpdate = distanceRunSinceLastUpdate;
}
}
}
I'm looking to get a result from a method which can take a while to complete and doesn't actually return the object, so I'd like to deal with it as effectively as possible. Here's an example of what I'm trying to achieve:
public static void main (String[] args) {
Object obj = someMethod();
System.out.println("The object is" + obj + ", wooh!");
}
public void callObject() {
// Sends request for the object
}
public void receiveObject(Object object) {
// Received the object
}
public Object someMethod() {
callObject();
// delay whilst the object is being received
// return received object once received, but how?
}
The method callObject will call to get the object, however a different method is called with the object in. I want someMethod() to be able to call for the object, and then return what it eventually receives, even though the actual call and receive are separate methods.
I've looked into using FutureTasks and Callables which I think is the way forward, I'm just not too sure how to implement it.
Sorry if I didn't explain myself too well, I'll give more information if necessary.
Thanks!
You could write a method, that kicks of some long running task asynchronously. You would then return a future object, that is empty but gets filled when the long running task is completed. In other programming languages, this is called a promise.
Here is an simple example. I created a method called someLongAsyncOperation which executes something that takes a while. To simulate this, I just sleep for 3 seconds before generating an answer.
import java.util.UUID;
import java.util.concurrent.*;
public class Test {
private static final ExecutorService executorService = Executors.newSingleThreadExecutor();
public Future<MyAnswer> someLongAsyncOperation(){
Future<MyAnswer> future = executorService.submit(() -> {
Thread.sleep(3000);
return new MyAnswer(UUID.randomUUID().toString());
});
return future;
}
public static void main(String[] args) throws Exception {
System.out.println("calling someLongAsyncOperation ...");
Future<MyAnswer> future = new Test().someLongAsyncOperation();
System.out.println("calling someLongAsyncOperation done.");
// do something else
System.out.println("wait for answer ...");
MyAnswer myAnswer = future.get();
System.out.printf("wait for answer done. Answer is: %s", myAnswer.value);
executorService.shutdown();
}
static class MyAnswer {
final String value;
MyAnswer(String value) {
this.value = value;
}
}
}
If you execute this little test class, you'll see, that someLongAsyncOperation returns fast, but when calling future.get(); we wait for the operation to complete.
You could now do something like starting of more than one longAsyncOperation, so they would run in parallel. And then wait until all of them are done.
Does this work as a starting point for you?
EDIT
You could implement someMethod like this:
public MyAnswer someMethod() throws ExecutionException, InterruptedException {
Future<MyAnswer> future = someLongAsyncOperation(); // kick of async operation
return future.get(); // wait for result
}
Which will make the async operation synchron again, by calling it and waiting for the result.
EDIT2
Here's another example that uses wait/notify:
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Test2 {
private static final ExecutorService executorService = Executors.newSingleThreadExecutor();
private Object receivedObject;
private final Object mutex = new Object();
public static void main (String[] args) throws InterruptedException {
Object obj = new Test2().someMethod();
System.out.println("The object is" + obj + ", wooh!");
executorService.shutdown();
}
public void callObject() {
System.out.println("callObject ...");
// Sends request for the object asynchronously!
executorService.submit(() -> {
// some wait time to simulate slow request
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// provide object to callback
receiveObject(UUID.randomUUID().toString());
});
System.out.println("callObject done.");
}
public void receiveObject(Object object) {
System.out.println("receiveObject ...");
synchronized (mutex) {
this.receivedObject = object;
mutex.notify();
}
System.out.println("receiveObject done.");
}
public Object someMethod() throws InterruptedException {
System.out.println("someMethod ...");
synchronized (mutex) {
callObject();
while(this.receivedObject == null){
mutex.wait();
}
}
System.out.println("someMethod done.");
return this.receivedObject;
}
}
someMethod waits until receivedObject exists. receiveObject notifies upon arrival.
You need a callback:
private abstract class Callback<T>{
run(T object);
}
public Object someMethod() {
callObject(new Callback<Object>()
{
#Override
public void run(Object object)
{
System.out.println("The object is" + object + ", wooh!");
}
})
}
public void callObject(Callback<Object> callback) {
// Sends request for the object
callback.run(object);
}
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
class ThreadExample implements Callable<String>{
#Override
public String call() throws Exception {
// TODO Auto-generated method stub
return "Ashish";
}
}
public class FutureThreadExample {
public static void main(String a[]) throws InterruptedException, ExecutionException {
ExecutorService executorService=Executors.newFixedThreadPool(1);
List <Future<String>>objList=new ArrayList<Future<String>>();
for(int i=0;i<10;i++) {
Future<String> obj=executorService.submit(new ThreadExample());
objList.add(obj);
}
for( Future<String> fut:objList) {
System.out.println(fut.get());
}
executorService.shutdown();
}
}
I want to use a CompletionService to process the results from a series of threads as they are completed. I have the service in a loop to take the Future objects it provides as they become available, but I don't know the best way to determine when all the threads have completed (and thus to exit the loop):
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
public class Bar {
final static int MAX_THREADS = 4;
final static int TOTAL_THREADS = 20;
public static void main(String[] args) throws Exception{
final ThreadPoolExecutor threadPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(MAX_THREADS);
final CompletionService<Integer> service = new ExecutorCompletionService<Integer>(threadPool);
for (int i=0; i<TOTAL_THREADS; i++){
service.submit(new MyCallable(i));
}
int finished = 0;
Future<Integer> future = null;
do{
future = service.take();
int result = future.get();
System.out.println(" took: " + result);
finished++;
}while(finished < TOTAL_THREADS);
System.out.println("Shutting down");
threadPool.shutdown();
}
public static class MyCallable implements Callable<Integer>{
final int id;
public MyCallable(int id){
this.id = id;
System.out.println("Submitting: " + id);
}
#Override
public Integer call() throws Exception {
Thread.sleep(1000);
System.out.println("finished: " + id);
return id;
}
}
}
I've tried checking the state of the ThreadPoolExecutor, but I know the getCompletedTaskCount and getTaskCount methods are only approximations and shouldn't be relied upon. Is there a better way to ensure that I've retrieved all the Futures from the CompletionService than counting them myself?
Edit: Both the link that Nobeh provided, and this link suggest that counting the number of tasks submitted, then calling take() that many times, is the way to go. I'm just surprised there isn't a way to ask the CompletionService or its Executor what's left to be returned.
See http://www.javaspecialists.eu/archive/Issue214.html for a decent suggestion on how to extend the ExecutorCompletionService to do what you're looking for. I've pasted the relevant code below for your convenience. The author also suggests making the service implement Iterable, which I think would be a good idea.
FWIW, I agree with you that this really should be part of the standard implementation, but alas, it's not.
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
public class CountingCompletionService<V> extends ExecutorCompletionService<V> {
private final AtomicLong submittedTasks = new AtomicLong();
private final AtomicLong completedTasks = new AtomicLong();
public CountingCompletionService(Executor executor) {
super(executor);
}
public CountingCompletionService(
Executor executor, BlockingQueue<Future<V>> queue) {
super(executor, queue);
}
public Future<V> submit(Callable<V> task) {
Future<V> future = super.submit(task);
submittedTasks.incrementAndGet();
return future;
}
public Future<V> submit(Runnable task, V result) {
Future<V> future = super.submit(task, result);
submittedTasks.incrementAndGet();
return future;
}
public Future<V> take() throws InterruptedException {
Future<V> future = super.take();
completedTasks.incrementAndGet();
return future;
}
public Future<V> poll() {
Future<V> future = super.poll();
if (future != null) completedTasks.incrementAndGet();
return future;
}
public Future<V> poll(long timeout, TimeUnit unit)
throws InterruptedException {
Future<V> future = super.poll(timeout, unit);
if (future != null) completedTasks.incrementAndGet();
return future;
}
public long getNumberOfCompletedTasks() {
return completedTasks.get();
}
public long getNumberOfSubmittedTasks() {
return submittedTasks.get();
}
public boolean hasUncompletedTasks() {
return completedTasks.get() < submittedTasks.get();
}
}
The code below is inspired by #Mark's answer, but I find it more convenient to use:
package com.example;
import java.util.Iterator;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class CompletionIterator<T> implements Iterator<T>, AutoCloseable {
private AtomicInteger count = new AtomicInteger(0);
private CompletionService<T> completer;
private ExecutorService executor = Executors.newWorkStealingPool(100);
public CompletionIterator() {
this.completer = new ExecutorCompletionService<>(executor);
}
public void submit(Callable<T> task) {
completer.submit(task);
count.incrementAndGet();
}
#Override
public boolean hasNext() {
return count.decrementAndGet() >= 0;
}
#Override
public T next() {
try {
return completer.take().get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
#Override
public void close() {
try {
executor.shutdown();
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
executor = null;
completer = null;
count = null;
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
This is how it can be used :
try(CompletionIterator service = new CompletionIterator()) {
service.submit(task1);
service.submit(task2);
// all tasks must be submitted before iterating, to avoid race condition
for (Future<Integer> future : service) {
System.out.printf("Job %d is done%n", future.get());
}
}
Answering to these questions gives you the answer?
Do your asynchronous tasks create other tasks submitted to CompletionService?
Is service the only object that is supposed to handle the tasks created in your application?
Based on reference documentation, CompletionService acts upon a consumer/producer approach and takes advantage of an internal Executor. So, as long as, you produce the tasks in one place and consume them in another place, CompletionService.take() will denote if there are any more results to give out.
I believe this question also helps you.
My take based on Alex R' variant. Implying this will only be called in one thread, so no atomics just plain int counter
public class CompletionIterator<T> implements Iterable<T> {
private int _count = 0;
private final CompletionService<T> _completer;
public CompletionIterator(ExecutorService executor) {
this._completer = new ExecutorCompletionService<>(executor);
}
public void submit(Callable<T> task) {
_completer.submit(task);
_count++;
}
#Override
public Iterator<T> iterator() {
return new Iterator<T>() {
#Override
public boolean hasNext() {
return _count > 0;
}
#Override
public T next() {
try {
T ret = _completer.take().get();
_count--;
return ret;
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
};
}
}