Может ли статический таймер Java обрабатывать несколько задач TimerTask, вызывающих метод cancel ()? - PullRequest
3 голосов
/ 10 августа 2010

Итак, я использую сервер Java, и в одном классе у меня есть статический таймер.Затем у меня есть другой класс, который имеет множество экземпляров, создаваемых и уничтожаемых в течение всей жизни программы, каждый со своим собственным TimerTask (используя статический Timer).Когда экземпляр уничтожается, он вызывает метод cancel () для TimerTask.

Проблема в том, что я не уверен, что это хороший дизайн, а также иногда я получаю ошибки, когда экземпляр создает и планирует егоTimerTask:

     java.lang.IllegalStateException: Timer already cancelled.

Вот некоторый код, чтобы показать, что я имею в виду.

/**
 * Starts scheduled tasks using TimerTask
 */
private void initTasks()
{
    // room heartbeat thread:  start immediately, run once every second
    roomHeartbeatTask = new RoomHeartbeatTask(this);
    RoomListExtension.roomHeartbeat.schedule(roomHeartbeatTask, 0, 1000);
    // add additional tasks here
}

/**
 * Cancels all tasks that have been started by this extension
 */
private void cancelTasks()
{
    roomHeartbeatTask.cancel();
}

1 Ответ

5 голосов
/ 10 августа 2010

Ошибка в том, что когда вы звоните cancel(), Timer становится «мертвым», и вы больше ничего не можете с ним сделать.

Из API :

Как только таймер был прерван, его поток выполнения завершается изящно, и на нем больше не может быть запланировано никаких задач.

У вас есть несколько вариантов:

  1. Избавьтесь от статического Timer и вместо этого держите отдельный экземпляр Timer в каждом объекте. Таким образом, когда объект уничтожен, вы также можете уничтожить Timer, не затрагивая другие TimerTask s. Это будет означать один поток таймера на объект.
  2. Сохраняйте статический Timer, но также держите в памяти (например, в ArrayList<TimerTask>) список всех задач в нем. Затем, когда объект уничтожается, вы воссоздаете статический объект Timer, используя список задач в памяти (минус тот, который соответствует объекту, который вы уничтожили). Следствием этого является то, что выполнение оставшихся TimerTask может потребовать некоторой подделки (особенно, если вы не хотите, чтобы все они «сгруппировались»).
  3. Расширьте или напишите свой собственный Timer -подобный класс, чтобы можно было удалить TimerTask s. (Кто-то, возможно, уже сделал это, я не знаю)
  4. Используйте ScheduledThreadPoolExecutor , который позволяет удалять задачи.
...