Мне нужны отдельные потоки для каждой выполняемой задачи, поэтому изменение архитектуры не вариант.
Если верно (например, при вызове функции внешней блокировки), создайте для них отдельные потоки и запустите их. Вы не можете создать пул потоков с ограниченным числом потоков, так как блокирующая функция в одном из потоков предотвратит вставку в него любого другого запускаемого объекта и не сильно увеличит создание пула потоков с одним потоком на задачу.
Я попытался сделать размер моего ThreadPool равным Runtime.getRuntime (). AvailableProcessors (), который пытался запустить все 500 потоков, но только 8 (4xhyperthreading) из них выполнялись.
Когда вы передаете объекты Thread, которые вы создаете, в пул потоков, он видит только то, что они реализуют Runnable
. Поэтому он будет запускаться каждый Runnable
до завершения. Любой цикл, который останавливает возврат метода run()
, не позволит запустить следующую поставленную в очередь задачу; например:
public static void main (String...args) {
ExecutorService executor = Executors.newFixedThreadPool(2);
for (int i = 0; i < 10; ++i) {
final int task = i;
executor.execute(new Runnable () {
private long lastRunTime = 0;
@Override
public void run () {
for (int iteration = 0; iteration < 4; )
{
if (System.currentTimeMillis() - this.lastRunTime > TIME_OUT)
{
// do your work here
++iteration;
System.out.printf("Task {%d} iteration {%d} thread {%s}.\n", task, iteration, Thread.currentThread());
this.lastRunTime = System.currentTimeMillis();
}
else
{
Thread.yield(); // otherwise, let other threads run
}
}
}
});
}
executor.shutdown();
}
распечатывает:
Task {0} iteration {1} thread {Thread[pool-1-thread-1,5,main]}.
Task {1} iteration {1} thread {Thread[pool-1-thread-2,5,main]}.
Task {0} iteration {2} thread {Thread[pool-1-thread-1,5,main]}.
Task {1} iteration {2} thread {Thread[pool-1-thread-2,5,main]}.
Task {0} iteration {3} thread {Thread[pool-1-thread-1,5,main]}.
Task {1} iteration {3} thread {Thread[pool-1-thread-2,5,main]}.
Task {0} iteration {4} thread {Thread[pool-1-thread-1,5,main]}.
Task {2} iteration {1} thread {Thread[pool-1-thread-1,5,main]}.
Task {1} iteration {4} thread {Thread[pool-1-thread-2,5,main]}.
Task {3} iteration {1} thread {Thread[pool-1-thread-2,5,main]}.
Task {2} iteration {2} thread {Thread[pool-1-thread-1,5,main]}.
Task {3} iteration {2} thread {Thread[pool-1-thread-2,5,main]}.
Task {2} iteration {3} thread {Thread[pool-1-thread-1,5,main]}.
Task {3} iteration {3} thread {Thread[pool-1-thread-2,5,main]}.
Task {2} iteration {4} thread {Thread[pool-1-thread-1,5,main]}.
...
показывает, что первые задачи (размер пула потоков) выполняются до того, как запланированы следующие задачи.
Что вам нужно сделать, это создать задачи, которые будут выполняться некоторое время, а затем запускать другие задачи. Как вы их структурируете, зависит от того, чего вы хотите достичь
- хотите ли вы, чтобы все задачи выполнялись одновременно, все ждут минуту, затем все снова запускаются одновременно или же задачи не синхронизированы друг с другом
- действительно ли вы хотели, чтобы каждая задача выполнялась с интервалом в одну минуту
- независимо от того, блокируются ли ваши задачи или нет, и поэтому действительно требуют отдельных потоков
- какое поведение ожидается, если задача блокируется дольше ожидаемого окна для запуска
- какое поведение ожидается, если задача блокируется дольше, чем частота повторения (блокируется более одной минуты)
В зависимости от ответов на них для координации задач может использоваться некоторая комбинация ScheduledExecutorService, семафоров или мьютексов. Самый простой случай - неблокирующие, несинхронные задачи, в этом случае используйте ScheduledExecutorService напрямую для запуска ваших исполняемых файлов раз в минуту.