我确实需要为每个正在运行的任务创建单独的线程,因此更改架构不是一个选项。
如果这是真的(例如,调用外部阻塞函数),那么为它们创建单独的线程并启动它们。您无法创建具有有限线程数的线程池,因为其中一个线程中的阻塞函数将防止任何其他可运行线程进入它,并且使用每个任务一个线程创建线程池不会带来太多好处。
我尝试将我的线程池大小设置为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)
{
++iteration;
System.out.printf("Task {%d} iteration {%d} thread {%s}.\n", task, iteration, Thread.currentThread());
this.lastRunTime = System.currentTimeMillis();
}
else
{
Thread.yield();
}
}
}
});
}
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 每分钟运行一次可运行实例。