2014-08-31 2 views
4

Предположим, у меня есть класс с методом, который я не хочу вызывать более одного раза в пять секунд (например, он запрашивает веб-сервер, который черным списком приложений, которые слишком часто отправляют запросы). Каков наилучший способ реализации этого?Каков правильный способ написать метод, который нельзя назвать слишком часто?

Решение, которое я придумал, заключается в том, чтобы метод хранил временную метку в статической переменной-члене каждый раз, когда она выполнялась по вызову System.currentTimeMillis(), и проверяйте эту отметку времени перед выполнением секретного кода. Но я нервничаю, что есть непредвиденные обстоятельства, которые я не предвидел, поэтому я хотел посмотреть, есть ли стандартный способ справиться с этой проблемой.

+5

Нет стандартного способа. Итак, вы идете с сохранением последней метки времени звонка в порядке. – talex

+1

Я бы сделал этот метод доступным для выполнения в другом потоке, чтобы не остановить текущее приложение для работы. В случае, если вы хотите, чтобы метод не мог выполняться так часто на уровне приложения, сделайте его «статическим» и используйте «статические» поля для его выполнения и вашего измерения времени, а также синхронизируйте его. –

+0

@ LuiggiMendoza Метод не обязательно должен быть статическим; на самом деле, * группа * методов может быть определена для использования одной и той же политики тайм-аута. Все такие методы (возможно, из экземпляров нескольких разных типов) относятся к тем же статическим данным синхронизации. –

ответ

0

Поскольку вы упомянули, что это веб-приложение, ваш метод будет делиться переменной timestamp среди всех вызовов, то есть из всех активных сеансов. Это не похоже на то, что вы хотели бы достичь.

Стандартным подходом «веб-приложения» является помещение объекта таймера в сеанс и запись фильтра, который будет управлять таймером.

0

Я не слышал о стандартном способе, но я решил эту проблему, так как я хотел слишком часто получать ntp-время, а сервер NTP блокировал мои запросы. Таким образом, следующий код сделал это для меня:

public static long getTime() { 
    // check whether a update should be done 
    if (System.currentTimeMillis() - updateTime > CLOCK_SYNC_INTERVAL_MS) { 
     // perform the update in a new thread 
     new Thread(new Runnable() { 
      @Override 
      public void run() { 
       updateClock(); 
      } 
     }).start(); 
    } 
    return System.currentTimeMillis() - updateTime + nts; 
} 
+1

Ведущие серверы приложений Java не любят потоки пользователей. Они хотят, чтобы вы получили поток из управляемого пула контейнера. – Alex

5

Используйте Guava RateLimiter. Простой пример:

public static void main(String[] args) { 
    callForeverWithRateLimited(); 
} 

public static void callForeverWithRateLimited() { 
    RateLimiter rateLimiter = RateLimiter.create(1); // 1 QPS (query per second) 
    while (true) { 
    if (rateLimiter.tryAcquire()) { 
     System.out.println("my rate was limited!"); 
    } 
    } 
} 
Смежные вопросы