2011-06-20 201 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); 
     } 
    }); 
}