Запуск Java-потока с интервалами

У меня есть поток, который нужно выполнять каждые 10 секунд. Этот поток содержит несколько вызовов (12-15) к базе данных на другом сервере. Кроме того, он также имеет доступ примерно к 3 файлам. Следовательно, будет довольно много накладных расходов ввода-вывода и сети.

Какая стратегия лучше всего подходит для выполнения вышеизложенного?

Один из способов - использовать метод сна вместе с циклом while, но это будет плохой дизайн.

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

Почему сон - плохой дизайн? Конечно, это будет не каждые 10 секунд, а каждые 10 + n секунд. Но вы все равно не можете гарантировать 10 секунд, если один из проходов занимает 12 секунд. Если вы просто пытаетесь минимизировать нагрузку на сервер, не имеет большого значения, спящий ли он или таймер.

paxdiablo 09.01.2009 04:41

Я называл сон вместе с циклом while как плохой дизайн. Поскольку решение о том, когда и как завершить поток, может быть не очень интуитивно.

Epitaph 09.01.2009 04:53
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
18
2
29 874
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Взгляните на классы Таймер и 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 символов - это всего лишь предложение!

jjnguy 09.01.2009 04:47

Я просто пробовал ввести "!" и я получаю ужасное сообщение «Пожалуйста, введите не менее 10 символов». под полем ввода, когда я нажимаю AddComment. На самом деле он не входит в комментарий. Как ты это сделал ??

paxdiablo 09.01.2009 07:13

Если вы наберете! <Много пробелов>. вы можете обмануть систему. Кажется, он считает пространство символом, а затем удаляет лишние, когда ему хочется.

jjnguy 09.01.2009 07:14

Да, нельзя ставить пробелы в начале или в конце, они должны быть посередине! Кто написал эту хрень? :-)

paxdiablo 09.01.2009 07:16

Один из вариантов - создать ScheduledExecutorService, для которого вы можете запланировать свою работу:

ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();
ex.scheduleWithFixedDelay(...);

Если вы решили использовать несколько потоков, вы можете создать ScheduledExecutorService с большим количеством потоков (опять же, через класс Executors).

Что касается количества потоков и того, что вы помещаете в каждый поток, с точки зрения производительности, я бы сказал, что это зависит от:

  • для вашего конкретного приложения может ли один поток действительно «работать», в то время как другой ожидает ввода-вывода?
  • будут ли ваши несколько потоков в конечном итоге «перебивать один и тот же ресурс» (например, читать из файлов в разных местах одного и того же dsk) и, таким образом, замедлять друг друга, или они будут одновременно использовать разные ресурсы?
Ответ принят как подходящий

Я считаю, что 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)».

Evan 09.01.2009 05:58

Это, безусловно, защитит; объявление doPeriodicWork как synchronized приведет к тому же результату и, вероятно, будет немного чище. При этом, вероятно, в doPeriodicWork есть более мелкие критические разделы, которые можно было бы защитить индивидуально при переходе в пул потоков.

Greg Case 09.01.2009 06:10

@GregCase: Если вы измените periodicTask во время работы executor, как вы заставите executor обновиться, чтобы использовать последнюю версию periodicTask во время выполнения?

ThreaT 04.08.2015 15:12

@ThreaT: нет возможности напрямую заменить экземпляр Runnable. У вас есть 2 варианта: отменить (используя ScheduledFuture, возвращаемый расписанием) и повторно отправить с новым Runnable, или настроить свой экземпляр Runnable, чтобы он имел такое состояние, чтобы он делегировал другому экземпляру объекта, а затем заменял этот экземпляр объекта на лету. Обратите внимание, если вы сделаете это, ваш Runnable, скорее всего, не сможет быть анонимным внутренним классом, как в примере в ответе; вам нужно будет как минимум объявить поле, в котором хранится экземпляр делегата, и где-нибудь сохранить ссылку, чтобы иметь возможность обновлять это поле.

Greg Case 04.08.2015 18:27

Другие вопросы по теме