Регистрация события в потоке с помощью функции обратного вызова - PullRequest
0 голосов
/ 21 февраля 2012

Я модифицирую свой сервер таким образом, чтобы каждый раз, когда он принимает соединение, он регистрировал событие тайм-аута в потоке с функцией обратного вызова. Таймаут может быть любым числом.

Существует только один поток времени ожидания (каждое соединение не назначено одному отдельному потоку времени ожидания).

Как бы я поступил так? Я думаю о запуске потока в main, но не уверен, как зарегистрировать в нем событие тайм-аута и как передать аргументы.

Ответы [ 2 ]

3 голосов
/ 21 февраля 2012

Использовать ScheduledExecutorService:

ScheduledExecutorService ses = Executors.newScheduledThreadPool(1);
void registerCallback() {
  ses.schedule(new MyCommand(), 30, TimeUnit.SECONDS);
}

Возвращает Future, который можно использовать для отмены выполнения, если вы хотите, иличтобы получить значение, возвращаемое MyCommand.

Если вы хотите запланировать команду, которая будет повторяться своевременно, вы можете использовать другие методы планирования: scheduleAtFixedRate и scheduleWithFixedDelay.

Если вам нужно перепланировать только некоторые условия или с разными скоростями или интервалами, я использовал одну технику, чтобы передать ScheduledExecutorService вашей команде (т. Е. new MyCommand(ses)) и позволить ей перенести свое расписание илиновая команда с соответствующей задержкой:

class MyCommand implements Runnable {
  private final ScheduledExecutorService ses;
  MyCommand(ScheduledExecutorService ses) { this.ses = ses; }
  private boolean shouldReschedule() { ... }
  private int getRescheduleTimeoutMs() { ... }
  @Override void run() {
    // do work
    ...
    // reschedule if needed
    if (shouldReschedule()) {
      // reschedule this command:
      ses.schedule(this, getRescheduleTimeoutMs(), TimeUnit.MILLISECONDS);
      // or else a new one:
      ses.schedule(new MyCommand(ses), ...);
    }
  }
}
0 голосов
/ 21 февраля 2012

Похоже, ответ @ Бруно сработал для вас. Для потомков другим способом было бы просто создать фоновый поток, который просыпался бы каждую секунду, чтобы увидеть, установлено ли соединение и проверить его возраст. Если вы хотите получить больше фантазии, вы можете установить время начала и поспать нужное количество секунд. Что-то вроде следующего псевдокода:

private AtomicReference<Socket> socketTimeoutRef = new AtomicReference<Socket>();
public void run() {
    while (true) {
        Thread.sleep(1000);
        SocketTimeout socketTimeout = socketTimeoutRef.get();
        if (socketTimeout == null) {
            continue;
        }
        if (socket is closed) {
            socketTimeoutRef.compareAndSet(socketTimeout, null);
        } else if (System.currentTimeMillis() >= socketTimeout.timeoutMillis) {
            try {
                close the socket;
            } catch (Exception e) {
                // ignore exceptions
            }
            socketTimeoutRef.compareAndSet(socketTimeout, null);
        }
    }
}
public void startTimeoutCounter(Socket socket) {
    socketRef.set(new SocketTimeout(socket));
}
private static class SocketTimeout {
    Socket socket;
    long timeoutMillis;
    public SocketTimeout(Socket socket) {
        this.socket = socket;
        timeoutMillis = System.currentTimeMillis() + SOCKET_TIMEOUT_MILLIS;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...