Как сделать задержку на java

Итак, Thread.sleep(), swing.Timer или util.Timer?
Когда встаёт вопрос о том, чтобы в программе одновременно трудилось несколько процессов, Java мгновенно предоставляет замечательный выбор. Это таймеры и потоки.
Каждый из этих способов имеет свои плюсы и минусы, не лишне было проверить их "на вшивость".
Начну с остановки потоков и таймера из пакета swing. Много описывать не буду, код хорошо задокументирован.
код TimerTest.java

Код:

/ Демонстрация работы с таймерами пакета java.swing. Показано три различных примера создания слушателя Таймеры из пакета java.util не проверяются, так как они весьма ненадёжны Задержки проверяются функциями currentTimeMillis() и nanoTime() Для проверки реальные задержки сравниваются с остановкой потоков Написано для сайта tv-games.ru (C) Leonis, 2015 / // импортируем необходимые пакеты // иначе получим ошибку: error: cannot find symbol import java.awt.event.; import javax.swing.Timer; import java.io.PrintStream; import java.io.FileOutputStream; import java.io.FileNotFoundException; / Основной класс, используемый для тестирования / class Loop implements ActionListener { boolean running=true; // программа работает пока running==true long k=0; // для запоминания миллисекунд double m=0; // среднее время между запусками таймера int timer2Delay=5000; // время срабатывания второго таймера в миллисекундах Timer timer, timer2; // два таймера. Первый рабочий, второй его прерывает public Loop() { System.out.println("Program started. Please wait..."); // без блока try получим следующую ошибку: // error: unreported exception FileNotFoundException; must be caught or declared to be thrown try { PrintStream pw = new PrintStream(new FileOutputStream("log.txt")); System.setOut(pw); // перенаправляем консольный вывод в файл log.txt } catch(FileNotFoundException e) { e.printStackTrace(); } timer2 = new Timer(timer2Delay, new ActionListener() { // анонимный слушатель public void actionPerformed(ActionEvent e) { running=false; // даём команду прервать цикл while // timer.stop(); // вызовет ошибку, анонимный слушатель не "видит" timer // error: local variable timer is accessed from within inner class; needs to be declared final } }); timer2.setRepeats(false); // второй таймер сработает только один раз и всё pause(0); // последовательно проверяем таймеры с различными задержками (мс) pause(1); pause(5); pause(10); pause(15); pause(20); } / Подкласс, используемый для проверки различных способов задержки времени / public void pause(int timerDelay) { System.out.print("Testing all timers. Now pause is "); System.out.print(timerDelay); System.out.println(" milliseconds..."); System.out.println("Phase one: timers. Please wait..."); timer = new Timer(timerDelay, this); // первый таймер. Выстреливает раз в 1 секунду без остановок // его слушатель в классе Loop: public void actionPerformed(ActionEvent e) timer.start(); // запускаем первый таймер timer2.start(); // запускаем второй таймер while(running) { // зацикливаем программу, пока не сработает второй таймер } timer.stop(); // принудительно останавливаем первый таймер System.out.println("Time interval in millis: " + m +" ms"); k=0; m=0; running=true; timer.removeActionListener(this); // удаляем текущего слушателя timer.addActionListener(new NanoTimer()); // назначаем нового слушателя, он проверяет nanoTime // обратите внимание, он создаётся как экземпляр класса NanoTimer() timer.start(); // запускаем первый таймер timer2.start(); // запускаем второй таймер while(running) { // зацикливаем программу, пока не сработает второй таймер } timer.stop(); // принудительно останавливаем первый таймер m/=1000000; // переводим в миллисекунды System.out.print("Time interval in nanos: "); System.out.format("%.1f",m); System.out.println(" (ms)"); / Здесь для сравнения идёт остановка главного потока на тот же интервал / System.out.println("Phase two: thread. Please wait..."); for(int i=0;i<10;i++) { // для верности повторяем процедуру 10 раз k=System.currentTimeMillis(); // без блока try получим следующую ошибку компиляции: // error: unreported exception InterruptedException; must be caught or declared to be thrown try { Thread.sleep(timerDelay); // главный поток засыпает на timerDelay миллисекунд } catch (InterruptedException e) { e.printStackTrace(); } m=(m+(System.currentTimeMillis()-k))/2.0; } System.out.println("Time interval in millis: " + m +" ms"); for(int i=0;i<10;i++) { k=System.nanoTime(); try { Thread.sleep(timerDelay); } catch (InterruptedException e) { e.printStackTrace(); } m=(m+(System.nanoTime()-k))/2.0; } m/=1000000; System.out.print("Time interval in nanos: "); System.out.format("%.1f",m); System.out.println(" (ms)\n"); } / "родной" слушатель / public void actionPerformed(ActionEvent e) { // код, который будет выполнять первый таймер if (k==0) k=System.currentTimeMillis(); else { m=(m+(System.currentTimeMillis()-k))/2.0; } k=System.currentTimeMillis(); } / ещё один слушатель / class NanoTimer implements ActionListener { public void actionPerformed(ActionEvent e) { // код, который будет выполнять первый таймер if (k==0) k=System.nanoTime(); else { m=(m+(System.nanoTime()-k))/2.0; } k=System.nanoTime(); } } } public class TimerTest{ public static void main(String[] args){ new Loop(); } }
Таймеры из пакета java.util мне рассматривать не хотелось. Слишком много с ними возни. Они достаточно топорно реализованы. Код ниже плохо задокументирован, кому будет надо - разберётся.
код ThreadTest2.java

Код:

/ Демонстрация работы с таймерами пакета java.util. Написано для сайта tv-games.ru (C) Leonis, 2015 / // импортируем необходимые пакеты // иначе получим ошибку: error: cannot find symbol import java.util.Timer; import java.util.TimerTask; import java.io.PrintStream; import java.io.FileOutputStream; import java.io.FileNotFoundException; / Основной класс, используемый для тестирования / class Loop { boolean running=true; // программа работает пока running==true int timer2Delay=5000; // время срабатывания второго таймера в миллисекундах Timer timer, timer2; // два таймера. Первый рабочий, второй его прерывает TimerTask timerTask, timerTask2; public Loop() { System.out.println("Program started. Please wait..."); // без блока try получим следующую ошибку: // error: unreported exception FileNotFoundException; must be caught or declared to be thrown try { PrintStream pw = new PrintStream(new FileOutputStream("log2.txt")); System.setOut(pw); // перенаправляем консольный вывод в файл log.txt System.setErr(pw); // перенаправляем консольный вывод ошибок в файл log.txt } catch(FileNotFoundException e) { e.printStackTrace(); } // pause(0); // нельзя, выскочит ошибка // Exception in thread "main" java.lang.IllegalArgumentException: Non-positive period. pause(1); // последовательно проверяем таймеры с различными задержками (мс) pause(5); pause(10); pause(15); pause(20); } / Подкласс, используемый для проверки задержки времени / public void pause(int timerDelay) { running=true; System.out.print("Testing timers. Now pause is "); System.out.print(timerDelay); System.out.println(" milliseconds..."); // Повторно использовать таймер нельзя. Надо создавать новый, иначе выскочит ошибка: // Exception in thread "main" java.lang.IllegalArgumentException: Non-positive period. timer = new Timer(); NanoTimer nt=new NanoTimer(); timerTask=nt; timer.scheduleAtFixedRate(timerTask, timerDelay, timerDelay); // первый таймер. Выстреливает раз в 1 секунду без остановок timerTask2 = new TimerTask() { // Определяем задачу public void run() { timer.cancel(); timer2.cancel(); running=false; } }; timer2 = new Timer(); // иначе Exception in thread "main" java.lang.NullPointerException timer2.schedule(timerTask2, timer2Delay); while(running) { // зацикливаем программу, пока не сработает второй таймер } double m=nt.getValue()/1000000; System.out.print("Time interval in nanos: "); System.out.format("%.1f",m); System.out.println(" (ms)"); } class NanoTimer extends TimerTask { long k=0; // для запоминания миллисекунд double m=0; // среднее время между запусками таймера public void run() { if (k==0) k=System.nanoTime(); else { m=(m+(System.nanoTime()-k))/2.0; } k=System.nanoTime(); } public double getValue() { return m; } } } public class TimerTest2{ public static void main(String[] args){ new Loop(); } }
Есть ещё ScheduledThreadPoolExecutor, но у меня уже нет сил это изучить. В документации сказано, что "Configuring ScheduledThreadPoolExecutor with one thread makes it equivalent to Timer."
Таймеры от сторонних разработчиков не рассматриваю.
Результаты очень интересные.
Thread, swing.Timer

Testing all timers. Now pause is 0 milliseconds...
Phase one: timers. Please wait...
Time interval in millis: 0.12545967849848738 ms
Time interval in nanos: 1,9 (ms)
Phase two: thread. Please wait...
Time interval in millis: 0.0019032733135913883 ms
Time interval in nanos: 0,0 (ms)
Testing all timers. Now pause is 1 milliseconds...
Phase one: timers. Please wait...
Time interval in millis: 0.0019258535174836652 ms
Time interval in nanos: 2,0 (ms)
Phase two: thread. Please wait...
Time interval in millis: 0.5019265826641963 ms
Time interval in nanos: 1,9 (ms)
Testing all timers. Now pause is 5 milliseconds...
Phase one: timers. Please wait...
Time interval in millis: 1.9484478393573503 ms
Time interval in nanos: 5,9 (ms)
Phase two: thread. Please wait...
Time interval in millis: 4.638530520273565 ms
Time interval in nanos: 5,9 (ms)
Testing all timers. Now pause is 10 milliseconds...
Phase one: timers. Please wait...
Time interval in millis: 5.86178019398294 ms
Time interval in nanos: 10,8 (ms)
Phase two: thread. Please wait...
Time interval in millis: 11.367928020187971 ms
Time interval in nanos: 10,7 (ms)
Testing all timers. Now pause is 15 milliseconds...
Phase one: timers. Please wait...
Time interval in millis: 10.729611829460866 ms
Time interval in nanos: 15,6 (ms)
Phase two: thread. Please wait...
Time interval in millis: 15.427355571506467 ms
Time interval in nanos: 15,6 (ms)
Testing all timers. Now pause is 20 milliseconds...
Phase one: timers. Please wait...
Time interval in millis: 15.60761994963609 ms
Time interval in nanos: 20,5 (ms)
Phase two: thread. Please wait...
Time interval in millis: 18.111812599697064 ms
Time interval in nanos: 20,5 (ms)


utils.Timer

Testing timers. Now pause is 1 milliseconds...
Time interval in nanos: 0,0 (ms)
Testing timers. Now pause is 5 milliseconds...
Time interval in nanos: 2,3 (ms)
Testing timers. Now pause is 10 milliseconds...
Time interval in nanos: 6,7 (ms)
Testing timers. Now pause is 15 milliseconds...
Time interval in nanos: 15,5 (ms)
Testing timers. Now pause is 20 milliseconds...
Time interval in nanos: 20,0 (ms)
вторая попытка:
Testing timers. Now pause is 1 milliseconds...
Time interval in nanos: 7,9 (ms)
Testing timers. Now pause is 5 milliseconds...
Time interval in nanos: 1,1 (ms)
Testing timers. Now pause is 10 milliseconds...
Time interval in nanos: 6,7 (ms)
Testing timers. Now pause is 15 milliseconds...
Time interval in nanos: 15,6 (ms)
Testing timers. Now pause is 20 milliseconds...
Time interval in nanos: 17,7 (ms)
третья попытка:
Testing timers. Now pause is 1 milliseconds...
Time interval in nanos: 0,2 (ms)
Testing timers. Now pause is 5 milliseconds...
Time interval in nanos: 2,2 (ms)
Testing timers. Now pause is 10 milliseconds...
Time interval in nanos: 5,8 (ms)
Testing timers. Now pause is 15 milliseconds...
Time interval in nanos: 15,6 (ms)
Testing timers. Now pause is 20 milliseconds...
Time interval in nanos: 16,4 (ms)


У меня Windows XP SP3, AMD Athlon 64 X2 5000+
Теперь о времени, измеряемом в наносекундах:
Как задержка потока, так и таймер swing срабатывают практически одинаково.
Погрешность в измерении существенна при маленьких временных отрезках (+1 миллисекунда), однако, такая точность как правило не нужна. Если требуемый интервал составляет 100 миллисекунд, то оба приёма гарантируют 109, то есть погрешность примерно 9%.
Для маленьких интервалов времени работа util.Timer неприятно удивляет. Разброс результатов от запуска к запуску сильно разнится, вдобавок, погрешность измерения времени очень большая. Любопытно, что для 100 миллисекунд разброс идёт от 102 до 107, что точнее конкурирующих технологий.
Если задержка составляет 1 секунду, то результаты совсем другие. swing.Timer даёт разброс от 1030 до 1144, причём, что currentMillis, что nanoTime не гарантируют никакой точности и по очереди соревнуются кто хуже.
Для 1 секунды остановка потока работает с невероятной точностью: 999. Это 0.1%, что очень круто.
util.Timer для 1 секунды демонстрирует стабильность: 996-998, что тоже очень хорошо.
То есть, что получается:
1. Thread.sleep() является самой точной технологией из всех рассмотренных.
2. swing.Timer тоже хорош, однако, во-первых, это зависимость от swing, во-вторых, по точности и стабильности эта технология немного уступает предыдущей
3. util.Timer следует использовать для интервалов времени выше 100. И всё равно, буду использовать его только в крайнем случае, он не так удобен в работе.
Работа функции currentTimeMillis() неудовлетворительная, далее я её не рассматриваю совсем. И в своих программах пользоваться не буду. System.nanoTime() считает точнее.

Источник: http://tv-games.ru/forum/blog.php?b=2030




Рекомендуем посмотреть ещё:


Закрыть ... [X]


VPF:Задержка выполнения проги - Форум программистов - Vingrad Статус о том что жизнь бумеранг

Как сделать задержку на java Задержка выполнения программы - Java SE (J2SE) - Киберфорум
Как сделать задержку на java Как сделать задержку в миллисекундах в java (ubuntu 16.04)
Как сделать задержку на java Как сделать задержку (delay) без таймера? - Java - RSDN
Как сделать задержку на java / Задержка выполнения программы - Форум Java
Как сделать задержку на java Ответы Как сделать задержку времени в java
Как сделать задержку на java Java - Как установить задержку в Android? - Qaru
Как сделать задержку на java 10 бесплатных инструментов для создания карт / Полезное / DAY
Анекдот К врачу-урологу тихонько постучались в дверь кабинета Вязание для крестин крючком - подборки, модели, фото Главная Портал Закупок Извлечь штифт из зуба Стоматология в Москве Импладент Когда стричь волосы Оракул и лунный календарь 2016 Крестильный набор для девочки крючком - описание, схемыфото Неаккуратненько Поздравления подруге на свадьбу трогательное до слез

ШОКИРУЮЩИЕ НОВОСТИ