Si nous devons exécuter des tâches de synchronisation simples au cours de notre processus de programmation, nous n'avons pas besoin de contrôler un contrôle complexe. Nous pouvons envisager d'utiliser les tâches de synchronisation de la minuterie dans JDK pour y parvenir. Le LZ suivant analyse le minuteur de la minuterie Java en fonction de son principe, de son exemple et de son défaut de temporisation.
1. Introduction
En Java, une tâche de synchronisation complète doit être effectuée par les classes de minuterie et de tricotasque. C'est ainsi qu'ils sont définis dans l'API. Timer: un outil qui l'utilise pour organiser des tâches que les threads effectuent dans des threads d'arrière-plan plus tard. Les tâches peuvent être exécutées une fois, ou elles peuvent être exécutées à plusieurs reprises. Tâche planifiée par Timemersk: Timer en tant que tâche exécutée ou répétée. Nous pouvons comprendre que Timer est un outil de minuterie utilisé pour planifier pour exécuter des tâches spécifiées dans un thread d'arrière-plan, et Timertask une classe abstraite dont la sous-classe représente une tâche qui peut être planifiée par Timer.
CLASSE DE TIMER <BR /> Dans le temporisateur de classe d'outils, quatre méthodes de constructeur sont fournies. Chaque constructeur démarre un fil de minuterie. Dans le même temps, la classe de temporisation peut garantir que plusieurs threads peuvent partager un seul objet de minuterie sans synchronisation externe, de sorte que la classe de minuterie est filée. Cependant, comme chaque objet Timer correspond à un seul thread d'arrière-plan, qui est utilisé pour exécuter toutes les tâches de minuterie en séquence, en général, le temps consacré à l'exécution de notre tâche de thread devrait être très court. Cependant, en raison de circonstances spéciales, le temps d'exécution d'une certaine tâche de temporisation est trop long, il sera donc "exclusivement" du thread d'exécution de la tâche de temporisation, et tous les fils suivants doivent attendre qu'il soit exécuté, ce qui retardera l'exécution des tâches suivantes et fera s'accumuler ces tâches ensemble. Nous analyserons la situation spécifique plus tard.
Lorsque le programme initialise la minuterie, la tâche de synchronisation sera exécutée en fonction du moment où nous avons défini. Timer fournit la méthode de planification, qui a plusieurs surcharges pour s'adapter à différentes situations, comme suit:
Calendrier (tâche Timemertass, date de date): Planifiez l'exécution de la tâche spécifiée à l'heure spécifiée.
Calendrier (tâche TIMERTASK, date de première fois, longue période): Planifiez la tâche spécifiée pour démarrer l'exécution de retard fixe répété à l'heure spécifiée.
Calendrier (tâche TIMERTASK, Long Delay): Planifie la tâche spécifiée à exécuter après le retard spécifié.
Calendrier (tâche Timertask, long retard, longue période): Planifiez la tâche spécifiée à exécuter à plusieurs reprises a fixé un retard après le retard spécifié.
En même temps, la méthode ScheduleAtFixeDrate est également surchargée. La méthode ScheduleAtFixeDrate est la même que le calendrier, mais leur objectif est différent, et la différence est analysée plus tard.
ScheduleAtFixeDrate (tâche Timertask, date de première fois, longue période): Planifiez la tâche spécifiée à exécuter à plusieurs reprises à un taux fixe à une heure spécifiée.
ScheduleAtFixeDrate (tâche Timertask, retard long, longue période): Planifiez la tâche spécifiée pour démarrer l'exécution répétée du taux fixe après le retard spécifié.
Timinerte
La classe TIMERTASK est une classe abstraite organisée par minuterie comme une tâche qui est exécutée ou répétée. Il a une méthode abstraite exécutée (), qui est utilisée pour effectuer les opérations à effectuer par la tâche de minuterie correspondante. Par conséquent, chaque classe de tâches spécifique doit hériter de Timertask, puis remplacer la méthode run ().
De plus, il a deux méthodes non abstraites:
booléen annule (): annuler cette tâche de minuterie.
Long ScheduleDexecutionTime (): renvoie le temps d'exécution planifié de l'exécution réelle la plus récente de cette tâche.
2. Exemples
2.1. Spécifiez le temps de retard pour exécuter les tâches de synchronisation
classe publique TimerTest01 {Timer Timer; public tinmerST01 (int time) {timer = new Timer (); Timer.Schedule (nouveau TimertAskTest01 (), temps * 1000); } public static void main (String [] args) {System.out.println ("Timer Begin ..."); New TinerTest01 (3); }} classe publique TimertAskTest01 étend Timertask {public void run () {System.out.println ("Time's Up !!!"); }} Résultats en cours:
Première impression: la minuterie commence ...
Imprimez en 3 secondes: le temps est écoulé !!!
2.2. Exécuter les tâches de synchronisation à l'heure spécifiée
classe publique TimerTest02 {Timer Timer; public tiperSt02 () {date heure = getTime (); System.out.println ("Spécifiez Time =" + Time); Timer = new Timer (); Timer.Schedule (new TimertAskTest02 (), temps); } public Date getTime () {calendar calendar = calendar.getInstance (); calendar.set (calendar.hour_of_day, 11); calendar.set (calendar.minute, 39); calendar.set (calendar.second, 00); Date heure = calendar.getTime (); heure de retour; } public static void main (String [] args) {new TimeTest02 (); }} classe publique TimertAskTest02 étend Timertask {@Override public void run () {System.out.println ("Exécuter des tâches de threads à l'heure spécifiée ..."); }} Lorsque le temps atteint 11:39:00, la tâche de fil sera exécutée, bien sûr, elle sera exécutée même si elle est supérieure à ce moment! ! Le résultat de l'exécution est:
Temps spécifié = mar 10 juin 11:39:00 CST 2014
Exécuter des tâches de threads à l'heure spécifiée ...
2.3. Après avoir retardé l'heure spécifiée, la tâche de synchronisation sera exécutée à l'intervalle spécifié.
classe publique TinerTest03 {Timer Timer; public tinmerST03 () {timer = new Timer (); Timer.Schedule (New TimertaSkTest03 (), 1000, 2000); } public static void main (String [] args) {new TimerST03 (); }} classe publique TimertAskTest03 étend Timertask {@Override public void run () {date date = new Date (this.ScheduleDeXecutionTime ()); System.out.println ("L'heure d'exécution de ce thread est:" + date); }} Résultats en cours:
Le temps d'exécuter ce fil est: mar 10 juin 21:19:47 CST 2014
Le temps d'exécuter ce fil est: mar 10 juin 21:19:49 CST 2014
Le temps d'exécuter ce fil est: mar 10 juin 21:19:51 CST 2014
Le temps d'exécuter ce fil est: mar 10 juin 21:19:53 CST 2014
Le temps d'exécuter ce fil est: mar 10 juin 21:19:55 CST 2014
Le temps d'exécuter ce fil est: mar 10 juin 21:19:57 CST 2014
................
Pour cette tâche de thread, si nous n'arrêtons pas la tâche, elle continuera à s'exécuter.
Pour les trois exemples ci-dessus, LZ l'a brièvement démontré et n'a pas expliqué l'exemple de la méthode ScheduleAtFixeDrate. En fait, cette méthode est la même que la méthode du calendrier!
2.4. Analyser le calendrier et le scheduleatFixeDrate
1.
Pour les deux méthodes, si le ScheduleDedexEcutionTime spécifié <= SystemCurrentTime, la tâche sera exécutée immédiatement. ScheduleDexecutiontime ne changera pas en raison de l'exécution excessive d'une tâche.
2) Planification (tâche Tirmertask, date de première fois, longue période), calendrier (tâche Timertask, long retard, longue période)
Ces deux méthodes sont un peu différentes des deux ci-dessus. Comme mentionné précédemment, la tâche du temporisateur sera retardée car la tâche précédente est exécutée pendant longtemps. Dans ces deux méthodes, l'heure planifiée de chaque tâche exécutée changera avec l'heure réelle de la tâche précédente, c'est-à-dire ScheduleDeXecutionTime (n + 1) = relexecutiontime (n) + délai d'épilé. C'est-à-dire que si la nième tâche provoque ce processus de temps d'exécution en raison d'une certaine situation, et enfin SystemCurrentTime> = ScheduleDexecutionTime (N + 1), il s'agit de la tâche N + 1 et ne sera pas exécutée en raison du temps. Il attendra l'exécution de la nième tâche avant l'exécution, puis cela mènera inévitablement à la version et à la modification de la mise en œuvre de la mise en œuvre de N + 2 ScheduleDexecutiontime, c'est-à-dire, planifié de temps en temps (n + 2) = relexeCutiontime (n + 1) + périodes. Par conséquent, ces deux méthodes accordent plus d'attention à la stabilité de l'intervalle de stockage.
3) ScheduleAtFixeDrate (tâche Timertask, date de première fois, longue période), scheduleatFixeDrate (tâche Timertask, long retard, longue période)
Comme mentionné précédemment, l'objectif des méthodes ScheduleAtFixeDrate et Schedule est différente. La méthode de planification se concentre sur la stabilité du temps d'intervalle de sauvegarde, tandis que la méthode ScheduleAtFixeDrate se concentre davantage sur le maintien de la stabilité de la fréquence d'exécution. Pourquoi le dites-vous, les raisons sont les suivantes. Dans la méthode de la planification, le retard de la tâche précédente entraînera le retard de la tâche de synchronisation après, tandis que la méthode ScheduleAtFixeDrate ne le fera pas. Si le temps d'exécution de la nième tâche est trop long, SystemCurrentTime> = ScheduleDexecutionTime (N + 1), il n'y aura pas d'attente pour exécuter la tâche N + 1 immédiatement. Par conséquent, la méthode de calcul de l'heure d'exécution de la méthode ScheduleAtFixeDrate est différente du calendrier, mais ScheduleDExEcutionTime (n) = FirstExecuTime + N * délai d'époque, et la méthode de calcul restera inchangée pour toujours. Par conséquent, ScheduleAtFixeDrate se concentre davantage sur le maintien de la fréquence d'exécution stable.
3. Défauts de la minuterie
3.1. Défauts de la minuterie
La minuterie de la minuterie peut être le temps (exécuter les tâches à l'heure spécifiée), le retard (tâches de retard à 5 secondes) et exécuter périodiquement des tâches (exécuter les tâches à 1 seconde), mais le temporisateur a quelques lacunes. Tout d'abord, la prise en charge de Timer pour la planification est basée sur le temps absolu, pas le temps relatif, il est donc très sensible aux changements de temps du système. Deuxièmement, le fil de minuterie n'attrapera pas d'exceptions. Si l'exception non contrôlée est lancée par Timertask, elle entraînera la fin du fil de minuterie. Dans le même temps, la minuterie ne reprendra pas l'exécution du thread, et il croira à tort que l'ensemble du thread de la minuterie sera annulé. Dans le même temps, Timertask, qui n'a pas encore été exécuté, ne sera plus exécuté et de nouvelles tâches ne peuvent pas être planifiées. Par conséquent, si Timertask lance une exception non contrôlée, Timer produira un comportement imprévisible.
1) Délai de délai de gestion du temporisateur <br /> Le minuteur précédent ne créera qu'une seule tâche de thread lors de l'exécution d'une tâche chronométrée. S'il y a plusieurs threads, si l'un des threads fait que le temps d'exécution de la tâche de thread est trop long pour une raison quelconque, et l'intervalle entre les deux tâches dépasse le temps entre eux, certains défauts se produiront:
classe publique TinerTest04 {Timer privé; Public Long Start; public tinmerST04 () {this.timer = new Timer (); start = System.currentTimemillis (); } public void timerOne () {timer.schedule (new TimeMtask () {public void run () {System.out.println ("TimerOn invoqué, le temps:" + (System.currenttimemillis () - Start)); try {Thread.Sleep (4000); // there dort 3000} Catch (interruptedExceptionne }}}}, 1000); } public void timertwo () {timer.schedule (new Timertask () {public void run () {System.out.println ("TimerOne invoqué, le temps:" + (System.CurrentTimemillis () - Start));}}, 3000); } public static void main (String [] args) lève une exception {TIMTERST04 test = new TinerTest04 (); test.timerone (); test.timertwo (); }} Selon notre réflexion normale, Timertwo doit être exécuté après 3s, et le résultat devrait être:
timeone invoqué, l'heure: 1001
timeone invoqué, l'heure: 3001
Mais les choses se sont opposées à mes attentes. Timerone dort (4000), dort 4 s et la minuterie est à l'intérieur de la minuterie, ce qui provoque le temps nécessaire pour que TimeOne dépasse l'intervalle. Le résultat:
timeone invoqué, l'heure: 1000
timeone invoqué, l'heure: 5000
2) La minuterie jette un défaut d'exception
Si Timertask lance un RuntimeException, Timer terminera toutes les tâches. comme suit:
classe publique TinerTest04 {Timer privé; public tinmerST04 () {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 ("vais-je l'exécuter ??");}}, 1000); } public static void main (String [] args) {TIMTERST04 test = new TimerTS04 (); test.timerone (); test.timertwo (); }} Résultat en cours d'exécution: Timerone lance une exception, provoquant la fin de la tâche TimertWo.
Exception dans Thread "TIMER-0" java.lang.runtimeException sur com.chenssy.timer.timertSt04 1 $.
Pour les défauts de la minuterie, nous pouvons considérer ScheduledThreadPoolExecutor en remplacement. Le temporisateur est basé sur le temps absolu et est plus sensible au temps du système, tandis que ScheduledThreadPoolExecutor est basé sur le temps relatif; La minuterie est un seul thread en interne, alors que ScheduledThreadPoolExecutor est un pool de threads en interne, il peut donc prendre en charge l'exécution simultanée de plusieurs tâches.
3.2. Remplacez la minuterie par ScheduleDExecutorService
1) Résoudre le problème:
classe publique ScheduleDexeCutOrest {private scheduleExECUTORService schedueXec; Public Long Start; ScheduleDexeCutOrest () {this.scheDuexec = exécutor.NewScheduleDThreadPool (2); this.start = System.currenttimemillis (); } public void timerOne () {schedueXec.schedule (new Runnable () {public void run () {System.out.println ("timerOn, le temps:" + (System.currenttimemillis () - start)); try {Thread.Sleep (4000);} cat (interruptedExect e) {e. }, 1000, timeunit.milliseconds); } public void timertwo () {scheduleExec.schedule (new Runnable () {public void run () {System.out.println ("Timertwo, le temps:" + (system.currenttimemillis () - start));}}, 2000, timeunit.MilliseConds); } public static void main (String [] args) {ScheduleDExECUTOrest test = new scheduleDExeCutOrest (); test.timerone (); test.timertwo (); }} Résultats en cours:
Timerone, l'heure: 1003
Timertwo, l'heure: 2005
2) Résoudre le problème deux
classe publique ScheduleDexeCutOrest {private scheduleExECUTORService schedueXec; Public Long Start; ScheduleDexeCutOrest () {this.scheDuexec = exécutor.NewScheduleDThreadPool (2); this.start = System.currenttimemillis (); } public void timerOne () {schedueXec.schedule (new Runnable () {public void run () {throw new RuntimeException ();}}, 1000, timeunit.milliseconds); } public void timertwo () {scheduleExec.scheDuleAtFixeDrate (new Runnable () {public void run () {System.out.println ("Timemertwo invoqué ....." ");}}, 2000 500, TimeUnit.MilliseConds); } public static void main (String [] args) {ScheduleDExECUTOrest test = new scheduleDExeCutOrest (); test.timerone (); test.timertwo (); }} Résultats en cours:
Timertwo invoqué ... Timertwo invoqué ... Timertwo invoqué ... Timertwo invoqué ... Timertwo invoqué ... Timertwo invoqué ... Timertwo invoqué ... Timertwo invoqué ... Timertwo invoqué ... Timertwo invoqué ............ Timertwo invoqué ...............................
Ce qui précède est l'intégralité du contenu de cet article. Il s'agit de tâches de synchronisation Java. J'espère que ce sera utile à votre apprentissage.