我有一个主要的for循环,它将请求发送到外部系统。外部系统可能需要几秒钟甚至几分钟才能回复 此外,如果请求数达到MAX_REQUESTS,则当前的for-loop应该休眠几秒钟。
这是我的情景。让我们说主要for-loop进入睡眠时间为5秒,因为它已达到MAX_REQUESTS。然后说来自callExternalSystem()的先前外部请求返回。当前处于SLEEP状态的主要for循环线程会发生什么?是否会中断并继续处理或继续休眠?
for(...){
...
while(numRequestsProcessing > MAX_REQUESTS){
Thread.sleep(SLEEP_TIME);
}
...
callExternalSystem();
}
提前致谢。
答案 0 :(得分:5)
除非你有一些代码来打断睡眠线程,否则它会继续睡眠直到所需的时间结束。如果您不希望这种情况发生,您可以使用wait()
/ notify()
而不是sleep()
,以便另一个线程可以按顺序通知对象主线程处于休眠状态唤醒它。那依赖于 另一个线程来注意到外部系统已经做出响应 - 当然 - 你不知道如何得到回复。
Semaphore
。每次主线程想要发出请求时,它都会获得许可。每次有响应时,都会发布许可证。然后,您只需要设置尽可能多的许可,就像您想要并发请求一样。如果您希望能够在主线程中指定超时,请使用tryAcquire
- 但如果您已经拥有尽可能多的未完成请求,请考虑您想要做什么。
答案 1 :(得分:3)
我会使用java.util.concurrent.Executors来创建一个包含MAX_REQUESTS个线程的线程池。为您一次发送的许多请求创建一个java.util.concurrent.CountDownLatch。将锁存器传递给发出请求的Runnables,它们在完成时调用锁存器上的countDown()。然后主线程在锁存器上调用await(timeout)。我还建议使用“Java Concurrency in Practice”这本书。
答案 2 :(得分:1)
一种方法是使用ThreadPoolExecutor,只要没有空闲线程就会阻塞。
ThreadPoolExecutor executor = new ThreadPoolExecutor(MAX_REQUESTS, MAX_REQUESTS, 60, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
try {
executor.getQueue().offer(r, Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
for(int i=0;i<LOTS_OF_REQUESTS;i++) {
final int finalI = i;
executor.submit(new Runnable() {
@Override
public void run() {
request(finalI);
}
});
}
另一种方法是让任务生成自己的请求。这样,每次线程并发时都会生成一个新请求。
ExecutorService executor = Executors.newFixedThreadPool(MAX_REQUESTS);
final AtomicInteger counter = new AtomicInteger();
for (int i = 0; i < MAX_REQUESTS; i++) {
executor.submit(new Runnable() {
@Override
public void run() {
int i;
while ((i = counter.getAndIncrement()) < LOTS_OF_REQUESTS)
request(i);
}
});
}