Неустойчивое поведение с ScheduledExecutorService

#java #multithreading

#java #многопоточность

Вопрос:

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

 class BeeperControl {

  private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);



  public void beepForAnHour() {

        final Runnable beeper = new Runnable() {

              public void run() {

                    System.out.println("beep");

              }

        };

        final ScheduledFuture<?> beeperHandle = scheduler.scheduleAtFixedRate(

                    beeper, 10, 10, TimeUnit.SECONDS);

        scheduler.schedule(new Runnable() {

              public void run() {

                    beeperHandle.cancel(true);

              }

        }, 60 * 60, TimeUnit.SECONDS);

  }



  public static void main(String[] args) {

        new BeeperControl().beepForAnHour();

  }
  

}

Но это только напечатало значение ‘beep’ 4 раза за 10 минут, когда оно должно было печатать его каждые 10 секунд. Кто-нибудь может мне помочь?

С уважением,

Carlos Ferreira

Редактировать:

Я добавил дополнительную информацию в инструкцию печати и запустил код на 2 разных компьютерах, один с Windows XP, а другой с Unix, посмотрите на результаты:

UNIX

звуковой сигнал в понедельник 17 октября 13:31:34 WEST 2011

звуковой сигнал в понедельник 17 октября 13:31:44 WEST 2011

звуковой сигнал в понедельник 17 октября 13:31:54 WEST 2011

звуковой сигнал в понедельник 17 октября 13:32:04 WEST 2011

звуковой сигнал в понедельник 17 октября 13:32:14 WEST 2011

звуковой сигнал в понедельник 17 октября 13:32:24 WEST 2011

звуковой сигнал в понедельник 17 октября 13:32:34 WEST 2011

Windows XP

звуковой сигнал в понедельник 17 октября 13:24:21 по восточному времени 2011

звуковой сигнал в понедельник 17 октября 13:25:54 по восточному времени 2011

звуковой сигнал в понедельник 17 октября 13:27:08 по восточному времени 2011

звуковой сигнал в понедельник 17 октября 13:28:03 по восточному времени 2011

звуковой сигнал в понедельник 17 октября 13:28:48 по восточному времени 2011

звуковой сигнал в понедельник 17 октября 13:29:40 по восточному времени 2011

звуковой сигнал в понедельник 17 октября 13:30:31 по восточному времени 2011

Комментарии:

1. вы работаете в Windows, возможно, на виртуальной машине? в Windows известны проблемы с синхронизацией, которые могут быть особенно серьезными, если вы работаете внутри виртуальной машины.

2. Я скопировал ваш код в Eclipse и добавил некоторые недостающие импорта. Работает нормально.

3. Я работаю на обычном ПК с Windows. Я также использую eclipse, и код работает некорректно. Я пробовал JDK1.6.0_24 и JRE1.5.0_15, и у меня была одна и та же проблема в обеих версиях.

4. Отлично работает в Windows 7 и Java 7.

5. Может ли это быть связано с высокой нагрузкой на ваш Windows-box?

Ответ №1:

Эта статья является хорошей отправной точкой для понимания проблемы. в основном, у таймеров Windows есть проблемы. Реализация jdk ScheduledExecutorService использует API-интерфейсы на Java на основе «nano time», которые являются проблематичными. Нам пришлось изменить наш код, чтобы он использовал java.util.Timer в Windows (которая использует API на основе миллисекунд и, похоже, надежно работает в Windows) и ScheduledExecutorService везде.

Ответ №2:

Код работает отлично. Возможно, вы чувствуете себя иначе из-за: 1) API говорит

Создает и выполняет периодическое действие, которое становится разрешенным сначала после заданной начальной задержки, а затем с заданным периодом; то есть выполнение начнется после initialDelay, затем initialDelay period, затем initialDelay 2 * period и так далее. Это отвечает поведению.

2) `scheduler.schedule(новый запускаемый() {

           public void run() {

                beeperHandle.cancel(true);

          }

    }, 60*60, TimeUnit.SECONDS);
  

ie в течение 1 часа. Следовательно, в течение примерно часа он будет отображать выходные данные.
3) Даже если вы измените время с 60 * 60 на 10, оно все равно не завершится. Потому что завершение работы никогда не вызывается.

 scheduler.schedule(new Runnable() {

          public void run() {
                beeperHandle.cancel(true);
                scheduler.shutdown();
          }

    }, 10, TimeUnit.SECONDS);
  

Теперь оно завершится должным образом

Комментарии:

1. Проблема заключается в интервале между исполнениями. Проверьте мою правку вопроса.

2. Извините, что неправильно истолковал это. На моем компьютере Win 7 он работает отлично. странно

Ответ №3:

Взгляните на эту статью. В нем обсуждается очень похожая проблема. Это может помочь в выяснении реальной проблемы.