0

所有,我有一個API調用被許多線程調用。唯一的問題是延遲下注。線程應該至少1秒。我意識到 - 無論是同步塊 - 如果一個線程在t1時刻調用api,則所有其他線程等待1秒,然後所有其他線程在t1 + 1秒調用api。這不是我想要的,所以我把整個等待塊放在同步塊中,只要一個線程正在等待所有其他線程塊。創建線程之間的延遲

This Works;不過,我認爲它不是最有效的方法。

任何建議,非常感謝。

private static volatile AtomicLong lastAPICall = new AtomicLong(); 

private void callAPI() { 

    // 1 sec plus a little extra 
    final long oneMS = 1 * 1000 + 100;    
    long lastCall = 0; 
    long timeDiff = 0; 

    synchronized (lastAPICall) { 
     timeDiff = System.currentTimeMillis() - lastAPICall.get(); 
     lastCall = lastAPICall.getAndSet(System.currentTimeMillis()); 
    } 
} 

if (System.currentTimeMillis() - lastCall < oneMS) { 
    synchronized (lastAPICall) { 
      try { 
       long sleep = oneMS - timeDiff; 
       Thread.sleep(oneMS - timeDiff); 
      } catch (InterruptedException ignore) {} 
      finally { 
       lastAPICall.set(System.currentTimeMillis()); 
       log.info("Thread: " + Thread.currentThread().getId() + " calling the api at this time: " + System.currentTimeMillis()); 
     } 
    } 
} 

try { 
// API CALL 
} 
catch (IOException t){ 
      throw t; 
} finally { 
    synchronized (lastAPICall) { 
    lastAPICall.set(System.currentTimeMillis()); 
    } 
} 

// Log files for running the code with 4 threads 
Thread: 35 calling the api at this time: 1456182353694 
Thread: 34 calling the api at this time: 1456182354795 
Thread: 37 calling the api at this time: 1456182355905 
Thread: 36 calling the api at this time: 1456182357003 
+0

您希望每個線程在前一個線程開始其調用之後或在前一個線程結束其調用之後等待一秒鐘嗎? –

+0

我希望每個線程在前一個線程開始呼叫後等待一秒鐘。 – blueSky

+0

第一個通話是否已經完成並不重要。 – blueSky

回答

0

如果您希望允許以某種速率調用API,你也不需要靜態原子的揮發。如果您在同步塊中使用它們,則不需要Atomic。

private static final long MAX_RATE = 1000; 
private static final Semaphore API_CALL_SEMAPHORE = new Semaphore(1); 
private volatile long lastCall; 

public void callApi() throws IOException, InterruptedException { 
    try { 
     API_CALL_SEMAPHORE.acquire(); 
     delayedCall(); 
    } catch (IOException | InterruptedException e) { 
     throw e; 
    } finally { 
     API_CALL_SEMAPHORE.release(); 
    } 
} 

private void delayedCall() throws InterruptedException, IOException { 
    long tryCallTime = System.currentTimeMillis(); 
    final long deltaTime = tryCallTime - lastCall; 
    if (deltaTime < MAX_RATE){ 
     final long sleepTime = MAX_RATE - deltaTime; 
     Thread.sleep(sleepTime); 
     tryCallTime += sleepTime; 
    } 
    // API CALL 
    lastCall = tryCallTime; // if you want to delay only succeed calls. 
} 
+0

Retardust添加的代碼保證只有一個線程在延遲的時間內調用API,在這種情況下,需要以同一時間通過多個線程調用API,從而以延遲1秒的方式調用API。不管之前的調用是否完成,多個線程都可以調用API。上面的代碼可以很容易地改變來完成。感謝您的迴應。 – blueSky