我的问题是:我最多可以运行三个并发任务。这些任务可以同时处理1到100个作业。我有很多线程经常提交单个工作,我想尽快回复它们。在一个任务中处理100个作业所花费的时间与在一个任务中处理1个作业所花费的时间相同。工作随机进入。提交作业的线程需要阻止,直到作业完成,或者超时。快速响应线程提交作业是这里的驱动因素。
所以我现在的逻辑是:如果有< 3个任务正在运行,并且一个工作到达,创建一个新任务来处理它自己的工作。如果有3个任务正在运行,请将作业放入队列并等待另一个任务完成,然后从队列中获取所有作业(限制100)并创建一个任务来处理所有这些任务。
我不太确定在Java中设置它的最佳方法。我创建了一个简单的信号量版本,它工作正常,但没有利用同时提交作业的能力。我应该如何最好地扩展它以完全满足我的要求? (没有要求使用信号量,它就是我到目前为止所拥有的信号量)。
private static final Semaphore semaphore = new Semaphore(3);
public static Response doJob(Job job) throws Exception
{
final boolean tryAcquire = this.semaphore.tryAcquire(this.maxWaitTime, TimeUnit.MILLISECONDS);
if (tryAcquire)
{
try
{
return doJobInNewTask(job); // we'd actually like to do all the jobs which are queued up waiting for the semaphore (if there are any)
}
finally
{
this.semaphore.release()
}
}
}
答案 0 :(得分:1)
您可以使用具有固定大小线程池的Executor
服务:
class ExecutorExample {
private final static ExecutorService executorService;
private final static long maxWaitTime = 5000;
static {
executorService = Executors.newFixedThreadPool(3);
}
private static class Response {}
private static class Job {}
public static Response doJob(final Job job) throws Exception {
final Future<Response> future = executorService.submit(
new Callable<Response>() {
@Override
public Response call() throws Exception {
return doJobInNewTask(job);
}
}
);
try {
// get() blocks until the task finishes.
return future.get(maxWaitTime, TimeUnit.MILLISECONDS);
}
catch (final TimeoutException e) {
// we timed out, so *try* to cancel the task (may be too late)
future.cancel(/*mayInterruptIfRunning:*/false);
throw e;
}
}
private static Response doJobInNewTask(final Job job) {
try { Thread.sleep(maxWaitTime / 2); }
catch (final InterruptedException ignored) {}
return new Response();
}
public static void main(final String[] args) {
final List<Thread> threads = new ArrayList<>();
for (int i = 0; i < 10; i++) {
final Thread t = new Thread() {
@Override
public void run() {
try {
System.out.println(doJob(new Job()));
}
catch (final Exception e) {
System.out.println(e.getClass().getSimpleName());
}
}
};
threads.add(t);
t.start();
}
for (final Thread thread : threads) {
try { thread.join(); }
catch (final InterruptedException ignored) {}
}
System.out.println("Done!");
}
}
输出:
ExecutorExample$Response@1fe4169
ExecutorExample$Response@9fdee
ExecutorExample$Response@15b123b
ExecutorExample$Response@bbfa5c
ExecutorExample$Response@10d95cd
ExecutorExample$Response@131de9b
TimeoutException
TimeoutException
TimeoutException
TimeoutException
Done!
这里的一个潜在问题是取消。由于调度不在您的手中,因此可能在您等待它之后启动任务,但 cancel()
之前的有机会完成它。结果不会传播,但如果任务有明显的副作用,这种方法可能会产生问题。