【问题标题】:Java Thread SleepJava 线程休眠
【发布时间】:2011-09-18 18:55:26
【问题描述】:

我有一个主 for 循环,可以向外部系统发送请求。外部系统可能需要几秒钟甚至几分钟才能做出响应。
此外,如果请求数达到 MAX_REQUESTS,当前的 for 循环应该 SLEEP 几秒钟。

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

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

}

提前致谢。

【问题讨论】:

  • 您是否添加了睡眠以试图让 numRequestsProcessing 下降?所以你不交换服务?一个固定的线程池会给你(或多或少)或通过等待/通知/条件进行线程间合作......?

标签: java multithreading


【解决方案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);
        }
    });
}

【讨论】:

    【解决方案2】:

    我会使用 java.util.concurrent.Executors 创建一个具有 MAX_REQUESTS 线程的线程池。为您一次发送的多个请求创建一个 java.util.concurrent.CountDownLatch。将锁存器传递给发出请求的 Runnable,它们在完成时在锁存器上调用 countDown()。然后主线程在闩上调用 await(timeout)。我还推荐《Java Concurrency in Practice》一书。

    【讨论】:

      【解决方案3】:

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

      编辑:听起来你真的应该使用Semaphore。每次主线程想要发出请求时,它都会获得一个许可。每次有响应时,都会释放许可证。然后,您只需要根据需要设置并发请求的数量即可。如果您希望能够在主线程中指定超时,请使用 tryAcquire - 但请考虑如果您已经有许多您真正满意的未完成请求,您想要做什么。

      【讨论】:

      • +1 虽然我会更进一步,并说在这里使用睡眠进行调度是一种反模式。肯定有一些事件可以与入站响应挂钩,以使唤醒具有确定性吗?
      • 好的,谢谢。 callExternalSystem() 实际上创建了另一个线程来调用外部系统。当它得到响应时,它会将 numRequestsProcessing 减 1。这就是主 for 循环线程如何知道何时不再进入睡眠状态。
      • @Marquinio:对。该线程可以通知调用者......但还有一个更好的选择。编辑。
      • 我对线程不太熟悉,但是在 while 循环中使用 Thread.sleep() 可能不是一个好主意。有某种类似 notify() 我认为会好得多,并且可能会提高 for 循环的性能。下次我会记住这一点。谢谢。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-28
      • 2020-05-23
      • 1970-01-01
      相关资源
      最近更新 更多