ExecutorService#invokeAll
может быть ключом здесь.
Вопрос немного сложен для понимания (может быть, даже , потому что вы пытались описать это точно? ;-)). Поэтому я создал пример, пытаясь обернуть вокруг него голову. Даже если это не , что вы намеревались, возможно, вы сможете объяснить, насколько это отличается от вашей цели, чтобы вопрос мог быть прояснен или другие могли написать лучший ответ.
В этом примере задачи создаются как Callable
объекты, которые помещаются в список. Такой список можно передать на ExecutorService#invokeAll
. (В вашем случае вы, вероятно, могли бы создать эти экземпляры из ваших Runnable
задач с помощью Executors#callable
). Всего создано 5 заданий. По умолчанию для выполнения каждой задачи требуется 2000 мс. Задача "C"
нечетная и занимает 8000 мс. Максимальное время выполнения должно быть 5000 мс.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class ExecutorServiceLimitTaskTime
{
private static Map<String, Long> taskSubmitMs =
new ConcurrentHashMap<String, Long>();
private static Map<String, Long> taskStartMs =
new ConcurrentHashMap<String, Long>();
private static Map<String, Long> taskFinishedMs =
new ConcurrentHashMap<String, Long>();
public static void main(String[] args) throws Exception
{
ExecutorService executorService = Executors.newFixedThreadPool(3);
List<String> tasks = Arrays.asList("A", "B", "C", "D", "E");
List<Callable<String>> callables = new ArrayList<Callable<String>>();
for (String task : tasks)
{
taskSubmitMs.put(task, System.currentTimeMillis());
callables.add(new Callable<String>()
{
@Override
public String call()
{
taskStartMs.put(task, System.currentTimeMillis());
long durationMs = 2000;
if (task.equals("C"))
{
durationMs = 8000;
}
performTask(task, durationMs);
if (!Thread.currentThread().isInterrupted())
{
taskFinishedMs.put(task, System.currentTimeMillis());
}
return task;
}
});
}
List<Future<String>> futures =
executorService.invokeAll(callables, 5000, TimeUnit.MILLISECONDS);
for (Future<String> future : futures)
{
try
{
future.get();
}
catch (CancellationException e)
{
System.out.println("One task was cancelled");
}
}
for (String task : tasks)
{
Long submitMs = taskSubmitMs.get(task);
Long startMs = taskStartMs.get(task);
Long finishedMs = taskFinishedMs.get(task);
if (finishedMs != null)
{
long waitMs = startMs - submitMs;
long runMs = finishedMs - startMs;
long totalMs = finishedMs - submitMs;
System.out.printf(
"Task %-3s waited %5d ms and ran %5d ms, total %5d ms\n",
task, waitMs, runMs, totalMs);
}
else
{
System.out.printf(
"Task %-3s was cancelled\n", task);
}
}
}
private static void performTask(String task, long durationMs)
{
System.out.println("Executing " + task);
try
{
Thread.sleep(durationMs);
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
System.out.println("Executing " + task + " DONE");
}
}
Резюме, напечатанное в конце, показывает этот результат:
Task A waited 16 ms and ran 2002 ms, total 2018 ms
Task B waited 3 ms and ran 2002 ms, total 2005 ms
Task C was cancelled
Task D waited 2005 ms and ran 2000 ms, total 4005 ms
Task E waited 2005 ms and ran 2000 ms, total 4005 ms
Это показывает, что
- Запуски, которые запускались немедленно, выполнялись в течение 2000 мс
- Задачи, которые должны были ждать других, также выполнялись в течение 2000 мс (но всего 4000 мс)
- Задание, которое заняло слишком много времени, было отменено через 5000 мс