Если нам нужно выполнить некоторые простые задачи времени во время нашего процесса программирования, нам не нужно выполнять сложный контроль. Мы можем рассмотреть возможность использования задач времени таймера в JDK для его достижения. В следующем LZ анализирует таймер таймера Java на основе его принципа, примера и дефекта таймера.
1. Введение
В Java полная задача времени должна быть выполнена классами Timer и Timertask. Вот как они определены в API. Таймер: инструмент, который использует его для распоряжения задач, которые потоки выполняют в фоновых потоках позже. Задачи могут быть выполнены один раз, или они могут быть выполнены неоднократно. Задача, запланированная Timertask: Timer как задача, которая выполняется или повторяется. Мы можем понять, что Timer - это инструмент таймера, используемый для планирования выполнения указанных задач в фоновом потоке, и Timertask Abstract Class, подкласс которой представляет собой задачу, которая может быть запланирована Timer.
Класс таймера предоставляет четыре метода конструктора в таймере класса инструментов. Каждый конструктор запускает поток таймера. В то же время класс таймера может гарантировать, что несколько потоков могут использовать один объект таймера без внешней синхронизации, поэтому класс таймера безопасен для потока. Однако, поскольку каждый объект таймера соответствует одному фоновому потоку, который используется для выполнения всех задач таймера в последовательности, в целом, время, потраченное на выполнение нашей задачи потока, должно быть очень коротким. Однако из -за особых обстоятельств время выполнения определенного задачи таймера слишком длинное, поэтому оно «исключительно» поток выполнения задачи таймера, и все последующие потоки должны ждать его выполнения, что задержит выполнение последующих задач и создаст эти задачи накапливаться вместе. Мы проанализируем конкретную ситуацию позже.
Когда программа инициализирует таймер, задача времени будет выполнена в соответствии со временем, которое мы установили. Таймер предоставляет метод расписания, который имеет несколько перегрузки для адаптации к различным ситуациям, следующим образом:
Расписание (задача Timertask, дата времени): Запланируйте выполнение указанной задачи в указанное время.
График (задача Timertask, дата первого периода, длительный период): Запланируйте указанную задачу, чтобы начать повторное выполнение фиксированной задержки в указанное время.
Расписание (задача Timertask, длинная задержка): планирует выполнять указанную задачу после указанной задержки.
График (задача Timertask, длительная задержка, длительный период): Запланируйте указанную задачу, которая будет выполнена неоднократно фиксированной задержкой после указанной задержки.
В то же время метод PradeAteAtFixEdRate также перегружен. Метод PradeUleatFixEdRate совпадает с графиком, но их фокус отличается, и разница анализируется позже.
ShaduleAtFixedRate (Timertask Task, Date Firstime, Long Period): Запланируйте указанную задачу, которая будет выполнена неоднократно с фиксированной скоростью в указанное время.
ShaduleAtFixedRate (Timertask Задача, длинная задержка, длительный период): Запланируйте указанную задачу, чтобы начать повторное выполнение с фиксированной скоростью после указанной задержки.
Timertask
Класс Timertask - это абстрактный класс, расположенный Timer как задачу, которая выполняется или повторяется. Он имеет абстрактный метод run (), который используется для выполнения операций, которые будут выполнены соответствующей задачей таймера. Следовательно, каждый конкретный класс задач должен наследовать Timertask, а затем переопределять метод run ().
Кроме того, он имеет два неабстрактных метода:
Boolean Cancel (): Отмените эту задачу таймера.
Long PredulleDexecutionTime (): возвращает запланированное время выполнения самого последнего фактического выполнения этой задачи.
2. Примеры
2.1. Укажите время задержки для выполнения задач времени
открытый класс Timertest01 {таймер таймер; public timertest01 (int time) {timer = new Timer (); timer.schedule (new timertasktest01 (), time * 1000); } public static void main (string [] args) {System.out.println ("Timer Begin ..."); новый Timertest01 (3); }} public Class TimerTaskTest01 Extends Timertask {public void run () {System.out.println ("Time's Up !!!"); }}Результаты работы:
Первый отпечаток:
таймер начинается ....
Печать за 3 секунды:
Время вверх !!!
2.2. Выполнить задачи времени в указанное время
открытый класс Timertest02 {таймер таймер; public timertest02 () {date time = gettime (); System.out.println ("Укажите время времени =" + time); timer = new Timer (); timer.schedule (new timertasktest02 (), time); } public date getTime () {календарный календарь = календарь.getInstance (); calendar.set (calendar.hour_of_day, 11); Calendar.Set (Calendar.minute, 39); Calendar.Set (Calendar.second, 00); Дата времени = календарь.gettime (); Время возвращения; } public static void main (string [] args) {new timertest02 (); }} public Class TimerTaskTest02 Extends TimerTask {@Override public void run () {System.out.println ("Заполнение потоков в указанное время ..."); }}Когда время достигнет 11:39:00, задача потока будет выполнена, конечно, оно будет выполнено, даже если оно больше этого времени! ! Результат исполнения:
Указанное время времени = вторник 10 июня 11:39:00 CST 2014 Указанное время для выполнения задач потока ...
2.3. После отложенности указанного времени задача времени будет выполнена в указанное время интервала.
открытый класс Timertest03 {таймер таймер; public timertest03 () {timer = new Timer (); timer.schedule (новый TimertaskTest03 (), 1000, 2000); } public static void main (string [] args) {new timertest03 (); }} public class TimerTaskTest03 Extends TimerTask {@Override public void run () {дата дата = новая дата (this.scheduledexecutiontime ()); System.out.println («Время для выполнения этого потока:» + date); }}Результаты работы:
Время для выполнения этой ветки: Tue 10 июня 21:19:47 CST 2014 Время для выполнения этой ветки: Tue 10 Jun 21:19:49 CST 2014 Время для выполнения этой ветки: Tue 10 июня 21:19:51 CST 2014 Время для выполнения этой ветки: Tue 10 21:19:53 CST 2014. 2014 время для выполнения этой ветки: вт 10 июня 21:19:57 CST 2014 ...............
Для этой задачи, если мы не остановим задачу, она продолжит работать.
Для приведенных выше трех примеров LZ просто кратко продемонстрировал это и не объяснил пример метода PradeAteFixEdrate. На самом деле, этот метод такой же, как метод расписания!
2.4. Анализ расписания и PradeAteAtFixEdRate
(1) Расписание (задача Timertask, дата времени), график (задача Timertask, длинная задержка)
Для обоих методов, если указанный PredulleDexecutionTime <= SystemCurrentTime, задача будет выполнена немедленно. DecaduLeDexecutition Time не изменится из -за чрезмерного выполнения задачи.
(2) Расписание (задача Timertask, дата первого периода, длительный период), график (задача Timertask, длительная задержка, длительный период)
Эти два метода немного отличаются от двух вышеуказанных. Как упоминалось ранее, задача таймера таймера будет отложена, потому что предыдущая задача выполняется в течение длительного времени. В этих двух методах запланированное время каждой выполняемой задачи будет изменяться с фактическим временем предыдущей задачи, то есть PhareDexeCutionTime (n+1) = realectcutiontime (n)+период времени. То есть, если NTH -задача вызывает этот процесс выполнения из -за какой -то ситуации, и, наконец, SystemCurrentTime> = PredulleDexecutionTime (n+1), это задача n+1 и не будет выполнена из -за времени. Он будет ждать выполнения NTH -задачи до выполнения, тогда это неизбежно приведет к выпуску и изменению реализации выполнения N+2. Следовательно, эти два метода уделяют больше внимания стабильности времени хранения.
(3) SeduleAtFixEdRate (Timertask Task, Date Firstime, Long Period), SeduleAtFixEdrate (задача Timertask, длинная задержка, длительный период)
Как упоминалось ранее, в центре внимания методов PradeAteFixedRate и расписания отличается. Метод расписания фокусируется на стабильности времени сбережений, в то время как метод PradeAteAtFixEdRate больше фокусируется на поддержании стабильности частоты выполнения. Почему вы так говорите, причины заключаются в следующем. В методе расписания задержка предыдущей задачи приведет к задержке задачи времени после него, в то время как метод PradeAteAtFixEdRate не будет. Если время выполнения NTH Задача слишком длинное, SystemCurrentTime> = PredulleDexeCutionTime (n+1), не будет немедленно ожидания, пока она не будет выполнить задачу n+1. Следовательно, метод расчета времени выполнения метода PradeAteFixedRate отличается от графика, но PredulleDexecutionTime (n) = FirstExeCuteTime +N*период времени, и метод расчета останется неизменным навсегда. Поэтому PradeuLeatFixEdRate больше фокусируется на поддержании стабильной частоты выполнения.
3. дефекты таймера
3.1. Дефекты таймера
Таймер таймера может времени (выполнять задачи в указанное время), задержка (задачи задержки через 5 секунд) и периодически выполнять задачи (выполнять задачи в 1 секунду), но у таймера есть некоторые недостатки. Прежде всего, поддержка Таймера для планирования основана на абсолютном времени, а не на относительном времени, поэтому он очень чувствителен к изменениям в системном времени. Во -вторых, поток таймера не поймает исключения. Если неконтролируемое исключение брошено Timertask, это приведет к прекращению таймера. В то же время таймер не возобновит выполнение потока, и он ошибочно полагает, что весь поток таймера будет отменен. В то же время, Timertask, который был запланирован еще не выполнен, больше не будет выполняться, а новые задачи не могут быть запланированы. Следовательно, если Timertask бросит неконтролируемое исключение, таймер приведет к непредсказуемому поведению.
(1) Дефекты задержки управления таймером. Прежде чем таймер создаст только одну задачу при выполнении временной задачи. Если есть несколько потоков, если один из потоков приведет к тому, что время выполнения задачи потока по какой -то причине будет слишком длинным, и будет происходить интервал между двумя задачами, возникнут некоторые дефекты: произойдут: произойдут некоторые дефекты:
открытый класс Timertest04 {частный таймер таймера; общественное долгое начало; public timertest04 () {this.timer = new Timer (); start = System.CurrentTimeMillis (); } public void -timerone () {timer.schedule (new timertask () {public void run () {System.out.println ("Вызов Timerone, Time:" + (System.currentTimeMillis () - Start); try {thread.sleep (4000); // Thread Sleeps 3000} CALLED (ERTERPECTEXCECEPTEXTEXCEPTEX ERCECEXTEXCECTEX e); }}}}, 1000); } public void timertwo () {timer.schedule (new timertask () {public void run () {System.out.println ("Вызов Timerone, Time:" + (System.currentTimeMillis () - start));}}, 3000); } public static void main (string [] args) бросает исключение {timertest04 test = new timertest04 (); test.timerone (); test.imertwo (); }}Согласно нашему нормальному мышлению, Timertwo должен быть выполнен после 3S, и результат должен быть:
Назвук Timerone, время: 1001 Timerone, время, время: 3001
Но все пошло против моих ожиданий. Timerone спит (4000), спит 4S, а таймер находится внутри таймера, что вызывает время, необходимое для превышения интервала Timeone. Результат:
Назвук Timerone, время: 1000 Timerone, время: 5000
(2) Таймер бросает дефект исключения. Если Timertask бросит Runtimeexception, таймер прекратит выполнение всех задач. следующее:
открытый класс Timertest04 {частный таймер таймера; public timertest04 () {this.timer = new Timer (); } public void -timerone () {timer.schedule (new timertask () {public void run () {throw new runtimeexception ();}}, 1000); } public void timertwo () {timer.schedule (new timertask () {public void run () {System.out.println ("Я выполняю его?");}}, 1000); } public static void main (string [] args) {timertest04 test = new timertest04 (); test.timerone (); test.imertwo (); }}Результат работы: Timerone бросает исключение, что приводит к прекращению задачи Timertwo.
Исключение в ветке "timer-0" java.lang.runtimeexception в com.chenssy.timer.timertest04 $ 1.run (timertest04.java:25) на java.util.timerthread.mainloop (Timer.java:555) на java.util.timerthread.run (Timer.java:555) на java.util.timerthread.
Для дефектов таймера мы можем считать reduledThreadPoolexeCutor в качестве замены. Таймер основан на абсолютном времени и более чувствителен к системному времени, в то время как PredultHreadPoolexeCutor основан на относительном времени; Timer - это единственный поток внутри, в то время как PredulledThreadPoolexeCutor - это пул потоков внутри, поэтому он может поддерживать одновременное выполнение нескольких задач.
3.2. Заменить таймер на cheduledExecutorservice
(1) Решите проблему один:
public Class PredicleDexeCutortest {private PredulleDexeCutorService preduexec; общественное долгое начало; WarededExecutortest () {this.scheduexec = executors.newschedudThreadpool (2); this.start = system.currenttimemilsis (); } public void -timerone () {praduexec.schedule (new Runnable () {public void run () {System.out.println ("Timerone, Time:" + (System.currentTimeMillis () - start); try {thread.sleep (4000);} Catch (ErruptureException e) {e.print ttrace); }, 1000, timeUnit.milliseconds); } public void timertwo () {shaduleExec.schedule (new Runnable () {public void run () {System.out.println ("Timertwo, Time:" + (System.currentTimeMillis () - start));}}, 2000, timeUnit.milliseconds); } public static void main (string [] args) {preduledExecutortest test = new goodledexeCutortest (); test.timerone (); test.imertwo (); }}Результаты работы:
Timerone, The Time: 1003 Timertwo, Time: 2005
(2) решить проблему две
public Class PredicleDexeCutortest {private PredulleDexeCutorService preduexec; общественное долгое начало; WarededExecutortest () {this.scheduexec = executors.newschedudThreadpool (2); this.start = system.currenttimemilsis (); } public void timerone () {praduexec.schedule (new Runnable () {public void run () {throw new runtimeexception ();}}, 1000, timeUnit.milliseconds); } public void timertwo () {shaduleExec.scheduleatfixedrate (new Runnable () {public void run () {System.out.println ("Timertwo вызывает .....");}}, 2000 500, TimeUnit.milliseconds); } public static void main (string [] args) {preduledExecutortest test = new goodledexeCutortest (); test.timerone (); test.imertwo (); }}Результаты работы:
Timertwo призвал ... Timertwo призвал ... Timertwo призвал ... Timertwo призвал ... Timertwo призвал ... Timertwo призвал ... Timertwo призвал ... Timertwo призвал ... Timertwo вызвал ... Timertwo вызвал ............ Timertwo вызывает .......................
4. Используйте таймер для достижения мяча
Примером в книге симуляции был пинбол, который заключался в том, чтобы нарисовать несколько кругов в назначенном положении на холсте, и после периода задержки он был повторно нарисован в ближайшем положении. Заставьте мяч, который кажется движущимся, и отрегулируйте задержку через компонент JSPINNER, чтобы управлять скоростью движения мяча.
Ballscanvas.java
Public Class Ballscanvas расширяет Canvas реализует ActionListener, FocusListener {Private Ball Balls []; // несколько шаров частный таймер таймера; Частный статический бал класса {int x, y; // координировать цвет цвета; // Color Boolean Up, слева; // Направление движения мяча (int x, int y, color) {this.x = x; this.y = y; this.color = color; up = Left = false; }} public ballscanvas (color colors [], int dellow) {// инициализировать цвет и задержать это. Balls = new Ball [colors.length]; for (int i = 0, x = 40; i <colors.length; i ++, x+= 40) {balls [i] = новый шар (x, x, colors [i]); } this.addfocuslistener (this); таймер = новый таймер (задержка, это); // Создать объект таймера, задержка Укажите таймер задержки.start (); } // Установить задержку public void setDelay (int delay) {timer.setDelay (delay); } // Нарисуйте публичную void paint (графика g) {for (int i = 0; i <balls.length; i ++) {g.setcolor (Balls [i] .color); // установить цветные шарики [i] .x = шарики [i] .left? шары [i] .x - 10: шарики [i] .x + 10; if (balls [i] .x <0 || balls [i] .x> = this.getWidth ()) {// изменение направления на горизонтальные шарики [i] .left =! Balls [i] .left; } Balls [i] .y = Balls [i] .Up? шары [i] .y - 10: шары [i] .y + 10; if (balls [i] .y <0 || balls [i] .y> = this.getheight ()) {// изменять направление на вертикальные шарики [i] .up =! Balls [i] .up; } G.filloval (шарики [i] .x, шарики [i] .y, 20, 20); // Нарисуйте круг указанного диаметра}} // Таймер // перекрасить} // Получить фокус @Override public void FocusGized (FocuseVent e) {timer.stop (); // Стоп таймер} // Потерянный фокус @Override public void Focuslost (FocuseVent e) {timer.restart (); // перезапуск таймера}}Ballsjframe.java
Class Ballsjframe расширяет JFrame Reflames Changelistener {Private Ballscanvas Ball; частный jspinner spinner; public ballsjframe () {super ("pinball"); this.SetBounds (300, 200, 480, 360); this.setDefaultCloseoperation (exit_on_close); Цвет цвета [] = {color.red, color.green, color.blue, color.magenta, color.cyan}; Ball = New Ballscanvas (цвета, 100); this.getContentPane (). Add (Ball); Jpanel panel = new jpanel (); this.getContentPane (). добавить (панель, "Юг"); panel.add (new jlabel ("delay")); spinner = new jspinner (); Spinner.SetValue (100); panel.add (spinner); Spinner.AddChangelistener (это); this.setvisible (true); } @Override public void stateChanged (изменение Event E) {// При изменении значения jspinner нажмите кнопку «Вверх» или «Вниз» jspinner или нажмите enter in jspinner ball.setdelay (integer.parseint (" + spinner.getvalue ())); } public static void main (string [] args) {new Ballsjframe (); }} Эффекты следующие: