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