У меня есть ThreadPoolExecutor, который, кажется, врет мне, когда я вызываю getActiveCount(). Однако я не сделал много многопоточного программирования, поэтому, возможно, я что-то делаю неправильно.
Здесь мой TPE
@Override
public void afterPropertiesSet() throws Exception {
BlockingQueue<Runnable> workQueue;
int maxQueueLength = threadPoolConfiguration.getMaximumQueueLength();
if (maxQueueLength == 0) {
workQueue = new LinkedBlockingQueue<Runnable>();
} else {
workQueue = new LinkedBlockingQueue<Runnable>(maxQueueLength);
}
pool = new ThreadPoolExecutor(
threadPoolConfiguration.getCorePoolSize(),
threadPoolConfiguration.getMaximumPoolSize(),
threadPoolConfiguration.getKeepAliveTime(),
TimeUnit.valueOf(threadPoolConfiguration.getTimeUnit()),
workQueue,
// Default thread factory creates normal-priority,
// non-daemon threads.
Executors.defaultThreadFactory(),
// Run any rejected task directly in the calling thread.
// In this way no records will be lost due to rejection
// however, no records will be added to the workQueue
// while the calling thread is processing a Task, so set
// your queue-size appropriately.
//
// This also means MaxThreadCount+1 tasks may run
// concurrently. If you REALLY want a max of MaxThreadCount
// threads don't use this.
new ThreadPoolExecutor.CallerRunsPolicy());
}
В этом классе у меня также есть DAO, который я передаю в свой Runnable (FooWorker
), например:
@Override
public void addTask(FooRecord record) {
if (pool == null) {
throw new FooException(ERROR_THREAD_POOL_CONFIGURATION_NOT_SET);
}
pool.execute(new FooWorker(context, calculator, dao, record));
}
FooWorker
запускает record
(единственный не одиночный) через конечный автомат через calculator
, затем отправляет переходы в базу данных через dao
, например:
public void run() {
calculator.calculate(record);
dao.save(record);
}
Как только мой основной поток будет создан, создавая новые задачи, я пытаюсь и жду, чтобы убедиться, что все потоки успешно завершены:
while (pool.getActiveCount() > 0) {
recordHandler.awaitTermination(terminationTimeout,
terminationTimeoutUnit);
}
То, что я вижу из выходных журналов (которые предположительно ненадежны из-за потоковой передачи), заключается в том, что getActiveCount() возвращает слишком рано слишком рано, а цикл while() выходит, а мои последние потоки все еще печатают вывод из calculator
.
Примечание. Я также попробовал вызов pool.shutdown()
, затем используя awaitTermination
, но затем в следующий раз, когда моя работа запущена, пул все еще отключается.
Мое единственное предположение заключается в том, что внутри потока, когда я отправляю данные в dao
(так как это singleton, созданный Spring в основном потоке...), java рассматривает поток неактивным, поскольку (я предполагаю ) он обрабатывает/ждет в основном потоке.
Интуитивно, основываясь только на том, что я вижу, это моя догадка. Но... Это действительно то, что происходит? Есть ли способ "сделать это правильно", не добавляя ручную добавленную переменную вверху run()
и уменьшаясь в конце для отслеживания количества потоков?
Если ответ "не проходит в дао", то разве мне не нужно "новое" DAO для каждого потока? Мой процесс уже (красивый, эффективный) зверь, но это действительно сосать.