Полная трассировка стека и более полный пример кода должны помочь прояснить, что происходит. Но в показанном вами коде выделяются несколько вещей.
Вызов основного задания
В вашем образце вы делаете
pool.execute(worker);
resultList = worker.invoke();
Это не тот способ, которым он должен работать.
Вызов «execute» отправляет задачу, что нормально, но она не будет ждать ее завершения. Итак, вы только что запустили вычисление без дескриптора при его завершении или результате.
Вызов invoke
самостоятельно - это не то, что вы обычно делаете, вы должны позволить pool
вызывать сам этот метод. Потому что он начнет выполнение задачи в вызывающем потоке без поддержки какого-либо пула. Так что вы можете даже заблокировать себя, если вы join
в нелогичном порядке.
«Предполагаемый» способ вызвать RecursiveTask<T>
- позвонить по номеру pool.invoke(task)
, который вернет вам T
(результат вычисления) или pool.submit(task)
, который вернет вам Future
.
Совместное использование состояния между задачами
Этот фрагмент кода внутри задачи может быть проблематичным:
List<Long> results = calcFactors(...);
results.addAll(f.join);
Это будет работать, если calcFactors
создаст свой собственный List
для возврата. Но если этот список распределяется между задачами, это означает, что несколько задач (и потоков) могут выполнять addAll
в одном экземпляре, что будет работать только в том случае, если список сможет его поддерживать (я думаю, что единственный одновременный List
в JDK это CopyOnWriteArrayList
).