I am using a bunch of callables to search a list in individual chunks, once one returns true, I want to cancel all the other running callables. future.cancel is not cancelling them
My NumberFinder
public class NumberFinderImpl implements NumberFinder {
// how many threads the exucutor will use to start the callables
private final int NUMBER_THREADS = 20;
// the amount of elements in the array we will search in each callable chunk
private final int CHUNK_ARRAY_SIZE = 5;
@Override
public boolean contains(int valueToFind, List<CustomNumberEntity> arrayToSearch) {
long startTime = System.nanoTime();
ExecutorService WORKER_THREAD_POOL = Executors.newFixedThreadPool(NUMBER_THREADS);
CompletionService<Boolean> completionService =
new ExecutorCompletionService<>(WORKER_THREAD_POOL);
int numberOfChunksNeeded = (int) Math.ceil(arrayToSearch.size() / CHUNK_ARRAY_SIZE);
// get a callable for each chunk search
List<Callable<Boolean>> callablesForEachChunkSearch =
getCallablesForEachChunk(
CHUNK_ARRAY_SIZE, numberOfChunksNeeded, valueToFind, arrayToSearch);
// start the callables and collect the futures
List<Future<Boolean>> futuresForCallables =
callablesForEachChunkSearch
.stream()
.map(completionService::submit)
.collect(Collectors.toList());
for (int j = 0; j < futuresForCallables.size(); j++) {
try {
// take().get() is blocking
// so if a callable is not done yet
// it will wait until it is before proceeding
Boolean chunkResult = completionService.take().get();
if (chunkResult) {
long endTime = System.nanoTime();
long timeTaken = endTime - startTime;
// TimeUnit
long timeInSeconds = TimeUnit.SECONDS.convert(timeTaken, TimeUnit.NANOSECONDS);
System.out.println("Search time in seconds" + timeInSeconds);
for (Future<Boolean> future : futuresForCallables) {
// cancel all the other running callables
future.cancel(true);
}
return true;
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
for (Future<Boolean> future : futuresForCallables) {
// cancel all the other running callables
future.cancel(true);
}
long endTime = System.nanoTime();
long timeTaken = endTime - startTime;
// TimeUnit
long timeInSeconds = TimeUnit.SECONDS.convert(timeTaken, TimeUnit.NANOSECONDS);
System.out.println("Search time in seconds" + timeInSeconds);
return false;
}
// get a list of callables that each search a certain chunk of the array
private List<Callable<Boolean>> getCallablesForEachChunk(
int chunkArraySize,
int numberOfChunksNeeded,
int valueToFind,
List<CustomNumberEntity> arrayToSearch) {
List<Callable<Boolean>> callableList = new ArrayList<>(numberOfChunksNeeded);
for (int i = 0; i < numberOfChunksNeeded; i++) {
int startPosForCallable = 0;
if (i > 0) {
startPosForCallable = i * chunkArraySize;
}
// dont let end pos go out of bounds
// if the chunk extends past the size, just set endPos as the end of the array
int endPosForCallable =
Math.min(startPosForCallable + chunkArraySize - 1, arrayToSearch.size());
Callable<Boolean> callableSearch =
new NumberFinderCallable(
arrayToSearch, valueToFind, startPosForCallable, endPosForCallable);
callableList.add(callableSearch);
}
return callableList;
}
My callable that does the searching
public class NumberFinderCallable implements Callable<Boolean> {
private List<CustomNumberEntity> arrayToSearch;
private int startPos;
private int endPos;
private int valueToSearchFor;
public NumberFinderCallable(
List<CustomNumberEntity> arrayToSearch, int valueToSearchFor, int startPos, int endPos) {
this.arrayToSearch = arrayToSearch;
this.startPos = startPos;
this.endPos = endPos;
this.valueToSearchFor = valueToSearchFor;
}
@Override
public Boolean call() {
System.out.println(
"Callable started, searching the chunk of array with start pos "
+ startPos
+ " and end pos "
+ endPos);
for (int i = startPos; i <= endPos; i++) {
System.out.println(
"Callable is comparing a number in pos "
+ i
+ " in the chunk with star pos "
+ +startPos
+ " and end pos "
+ endPos);
if (FastestComparator.compare(valueToSearchFor, arrayToSearch.get(i)) == 0) {
System.out.println("element found in pos " + i + ". Returning true");
return true;
}
}
return false;
}
}
I can see from the logs even after a true result is found and all the futures are cancelled that the threads are still going