2011-06-20 163 views
1

我有一个主要的for循环发送请求到外部系统。外部系统可能需要几秒钟甚至几分钟才能回应。
另外,如果请求数量达到MAX_REQUESTS,当前的for-loop应该会休眠几秒钟。Java线程睡眠

这是我的场景。假设主循环进入睡眠5秒钟,因为它已达到MAX_REQUESTS。然后说一个以前的外部请求从callExternalSystem()返回。当前处于SLEEP状态的主要for循环线程会发生什么情况?它会中断并继续处理或继续睡眠?

for(...){ 
    ... 
    while(numRequestsProcessing > MAX_REQUESTS){ 
    Thread.sleep(SLEEP_TIME); 
    } 
    ... 
callExternalSystem(); 

} 

在此先感谢。

+0

您是否在尝试允许numRequestsProcessing关闭时添加睡眠?所以你不交换服务?一个固定的线程池会给你(或多或少)或通过等待/ notifiy /条件进行线程间合作。 – Toby

回答

5

除非你有一些代码来中断睡眠线程,它将继续睡眠,直到所需的时间过去。如果您不希望发生这种情况,您可以使用wait()/notify()而不是sleep(),以便另一个线程可以通知对象主线程正在休眠,以唤醒它。那依靠另一个线程要注意外部系统已经响应,当然 - 你不清楚如何得到回复。

编辑:这听起来像你真的应该使用Semaphore。主线程每次要发出请求时,都会获得许可证。每次有回应时,都会发布许可证。然后你只需要设置许可证就可以得到你想要的并发请求。如果您希望能够在主线程中指定超时时间,请使用tryAcquire - 但如果您已经拥有尽可能多的未满意的请求,请考虑想要执行的操作。

+1

+1虽然我会走得更远,并说这里使用睡眠时间表是一个反模式。当然,有一些事件可以吸引入境响应,使重新唤醒的确定性? –

+0

好的,谢谢。 callExternalSystem()实际上会创建另一个线程来调用外部系统。当它得到响应时,它会将numRequestsProcessing减1。这就是主要的for-loop线程知道什么时候不再去睡觉的原因。 – Marquinio

+0

@Marquinio:对。该线程*可以*通知呼叫者......但是有一个更好的选择。编辑。 –

3

我会使用java.util.concurrent.Executors创建一个MAX_REQUESTS线程的线程池。无论发送多少请求,都要创建一个java.util.concurrent.CountDownLatch。将锁存器传递给发出请求的Runnables,完成时它们会在锁存器上调用countDown()。主线程然后调用闩锁上的等待(超时)。我还会推荐一本书“实践中的Java并发”。

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); 
     } 
    }); 
}