【问题标题】:Creating delay between threads在线程之间创建延迟
【发布时间】:2016-02-22 23:58:44
【问题描述】:

所有,我有一个由许多线程调用的 api 调用。唯一的问题是延迟赌注。线程应至少为 1 秒。我意识到 - 没有同步块 - 如果一个线程在时间 t1 调用 api,那么所有其他线程等待 1 秒,然后所有其他线程在 t1 + 1 秒调用 api。这不是我想要的,所以我将整个等待块放在同步块中,只要一个线程正在等待所有其他线程块。

这行得通;但是,我认为这不是最有效的方法。

非常感谢任何建议。

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

【问题讨论】:

  • 您希望每个线程在前一个线程开始调用后等待一秒钟,还是在前一个线程结束调用后等待一秒钟?
  • 我希望每个线程在前一个线程开始调用后等待一秒钟。
  • 第一次通话是否已经结束并不重要。

标签: java multithreading synchronized volatile synchronized-block


【解决方案1】:

如果您想允许以某种速率调用 API。此外,您不需要 volatile 与静态 Atomic。如果你在同步块中使用它们,你就不需要 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.
}

【讨论】:

  • Retardust添加的代码保证在延迟时间内只有一个线程调用API,需要的是多个线程同时调用API,以一种调用延迟的方式1 秒。无论之前的调用是否完成,多个线程都可以调用 API。上面的代码可以很容易地改变来实现这一点。感谢您的回复。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-07
  • 2021-03-18
  • 2020-07-15
  • 1970-01-01
相关资源
最近更新 更多