У меня есть поток, который нужно выполнять каждые 10 секунд. Этот поток содержит несколько вызовов (12-15) к базе данных на другом сервере. Кроме того, он также имеет доступ примерно к 3 файлам. Следовательно, будет довольно много накладных расходов ввода-вывода и сети.
Какая стратегия лучше всего подходит для выполнения вышеизложенного?
Один из способов - использовать метод сна вместе с циклом while, но это будет плохой дизайн.
Будет ли полезен в этом случае класс, похожий на Timer? Кроме того, не было бы лучше создать еще пару потоков (один для ввода-вывода и один для JDBC), вместо того, чтобы запускать их в одном потоке?
Я называл сон вместе с циклом while как плохой дизайн. Поскольку решение о том, когда и как завершить поток, может быть не очень интуитивно.




Взгляните на классы Таймер и TimerTask. Они именно то, что вам нужно.
Вы можете создать реализацию TimerTask, которая принимает ваш объект потока в конструкторе.
Затем метод запуска вызовет метод запуска потоков.
// Perhaps something like this
Timer t = new Timer();
t.scheduleAtFixedRate(yourTimerTask, 0, 10 * 1000);
// Hopefully your task takes less than 12 seconds
10 символов - это всего лишь предложение!
Я просто пробовал ввести "!" и я получаю ужасное сообщение «Пожалуйста, введите не менее 10 символов». под полем ввода, когда я нажимаю AddComment. На самом деле он не входит в комментарий. Как ты это сделал ??
Если вы наберете! <Много пробелов>. вы можете обмануть систему. Кажется, он считает пространство символом, а затем удаляет лишние, когда ему хочется.
Да, нельзя ставить пробелы в начале или в конце, они должны быть посередине! Кто написал эту хрень? :-)
Один из вариантов - создать ScheduledExecutorService, для которого вы можете запланировать свою работу:
ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();
ex.scheduleWithFixedDelay(...);
Если вы решили использовать несколько потоков, вы можете создать ScheduledExecutorService с большим количеством потоков (опять же, через класс Executors).
Что касается количества потоков и того, что вы помещаете в каждый поток, с точки зрения производительности, я бы сказал, что это зависит от:
Я считаю, что ScheduledExecutorService - отличный способ сделать это. Возможно, он немного сложнее, чем Timer, но дает большую гибкость при обмене (например, вы можете выбрать использование одного потока или пула потоков; для этого требуются единицы, отличные от миллисекунд).
ScheduledExecutorService executor =
Executors.newSingleThreadScheduledExecutor();
Runnable periodicTask = new Runnable() {
public void run() {
// Invoke method(s) to do the work
doPeriodicWork();
}
};
executor.scheduleAtFixedRate(periodicTask, 0, 10, TimeUnit.SECONDS);
Если бы вы не использовали однопоточный исполнитель, я мог бы на всякий случай заключить вызов doPeriodicWork () в блок «synchronized (this)».
Это, безусловно, защитит; объявление doPeriodicWork как synchronized приведет к тому же результату и, вероятно, будет немного чище. При этом, вероятно, в doPeriodicWork есть более мелкие критические разделы, которые можно было бы защитить индивидуально при переходе в пул потоков.
@GregCase: Если вы измените periodicTask во время работы executor, как вы заставите executor обновиться, чтобы использовать последнюю версию periodicTask во время выполнения?
@ThreaT: нет возможности напрямую заменить экземпляр Runnable. У вас есть 2 варианта: отменить (используя ScheduledFuture, возвращаемый расписанием) и повторно отправить с новым Runnable, или настроить свой экземпляр Runnable, чтобы он имел такое состояние, чтобы он делегировал другому экземпляру объекта, а затем заменял этот экземпляр объекта на лету. Обратите внимание, если вы сделаете это, ваш Runnable, скорее всего, не сможет быть анонимным внутренним классом, как в примере в ответе; вам нужно будет как минимум объявить поле, в котором хранится экземпляр делегата, и где-нибудь сохранить ссылку, чтобы иметь возможность обновлять это поле.
Почему сон - плохой дизайн? Конечно, это будет не каждые 10 секунд, а каждые 10 + n секунд. Но вы все равно не можете гарантировать 10 секунд, если один из проходов занимает 12 секунд. Если вы просто пытаетесь минимизировать нагрузку на сервер, не имеет большого значения, спящий ли он или таймер.