1 introduction
Selon la conception Quartz, un emploi peut lier plusieurs Trigger, va inévitablement rencontrer des problèmes de concurrence.
2 simultanées
2.1 reproductibilité
Écrivons un exemple de concurrence:
1 / ** 2 * @author pancc 3 * @version 1,0 4 * / 5 publique classe AcceptConcurrentDemo { 6 7 publique statiques vides main (String [] args) lance SchedulerException, InterruptedException { 8 JobDetail détail = JobBuilder.newJob (AcceptConcurrentJob. Class ) 9 .withIdentity ( "détail", "group0" ) 10 .build (); 11 12 13 gâchette =TriggerBuilder.newTrigger () 14 .withIdentity ( "ben_trigger" ) 15 .usingJobData ( "name", "ben" ) 16 .startNow () 17 .build (); 18 19 de déclenchement des déclencheurs = TriggerBuilder.newTrigger () 20 .withIdentity ( "mike_trigger" ) 21 .usingJobData ( "name", "micro" ) 22 .forJob ( "détail", "group0" ) 23 .startNow () 24 .build (); Planificateur Scheduler = nouveau StdSchedulerFactory () getScheduler (). 28 29 scheduler.start (); 30 scheduler.scheduleJob (détail de déclenchement); 31 scheduler.scheduleJob (déclencheurs); 32 / * 33 * 6秒钟后关闭 34 * / 35 Thread.sleep (6_000); 36 scheduler.shutdown (); 37 } 38 39 @data 40 publics statiques classe AcceptConcurrentJob outils Job { 41 privé nom de chaîne; 42 43 @Override 44 publique vide execute (contexte JobExecutionContext) { 45 try { 46 System.out.printf ( "i am% s \ n" , nom); 47 Thread.sleep (2_000); 48 } captures (InterruptedException e) { 49 e.printStackTrace (); 50 } 51 } 52 } 53 }
S'il vous plaît noter que le haut de la page Détails de l' identité, est réglé sur group0.detail, nous avons créé deux le déclenchement , le second déclencheur lorsqu'il est créé en spécifiant l' identité se lient à la cible d' emploi, puis soumettre ce Job , et deux Trigger, peut nous voyons deux déclencheurs exécutent simultanément la méthode de démarrage d' un emploi
Le code peut être simplifié ci-dessus pour la forme suivante:
1 / ** 2 * @author pancc 3 * @version 1,0 4 * / 5 publique classe AcceptConcurrentDemo { 6 7 publique statiques vides main (String [] args) lance SchedulerException, InterruptedException { 8 JobDetail détail = JobBuilder.newJob (AcceptConcurrentJob. Class ) 9 .withIdentity ( "détail", "group0" ) 10 .build (); 11 12 13 gâchette =TriggerBuilder.newTrigger () 14 .withIdentity ( "ben_trigger" ) 15 .usingJobData ( "name", "ben" ) 16 .startNow () 17 .build (); 18 19 de déclenchement des déclencheurs = TriggerBuilder.newTrigger () 20 .withIdentity ( "mike_trigger" ) 21 .usingJobData ( "name", "micro" ) 22 .startNow () 23 .build (); 24 25 26 ordonnanceur Scheduler = nouveauStdSchedulerFactory () getScheduler (). 27 28 scheduler.start (); 29 scheduler.scheduleJob (détail, Sets.newHashSet (déclencheur, déclencheurs), vrai ); 30 / * 31 * 6秒钟后关闭 32 * / 33 Thread.sleep (6_000); 34 scheduler.shutdown (); 35 } 36 37 @data 38 publique statique classe AcceptConcurrentJob met en œuvre Job { 39 privé nom de chaîne; 40 41 @Override 42 publique vide exécution (contexte JobExecutionContext) { 43 essayer { 44 System.out.printf ( "i am% s \ n" , nom); 45 Thread.sleep (2_000); 46 } captures (InterruptedException e) { 47 e.printStackTrace (); 48 } 49 } 50 } 51 }
2.2 éviter la concurrence
Afin d'éviter la concurrence, nous pouvons utiliser l'annotation @ officielle de DisallowConcurrentExecution , par l'augmentation de la classe ce commentaire, on peut observer un deuxième processus a été faire la queue déclencheur:
1 / ** 2 * @author pancc 3 * @version 1,0 4 * / 5 publique classe RejectConcurrentDemo { 6 7 publique statiques vides main (String [] args) jetés SchedulerException, InterruptedException { 8 JobDetail détail = JobBuilder.newJob (RejectConcurrentJob. Class ) 9 .withIdentity ( "détail", "group0" ) 10 .build (); 11 12 13 gâchette =TriggerBuilder.newTrigger () 14 .withIdentity ( "ben_trigger" ) 15 .usingJobData ( "name", "ben" ) 16 .startNow () 17 .build (); 18 19 de déclenchement des déclencheurs = TriggerBuilder.newTrigger () 20 .withIdentity ( "mike_trigger" ) 21 .usingJobData ( "name", "micro" ) 22 .forJob ( "détail", "group0" ) 23 .startNow () 24 .build (); Planificateur Scheduler = nouveau StdSchedulerFactory () getScheduler (). 28 29 scheduler.start (); 30 scheduler.scheduleJob (détail de déclenchement); 31 scheduler.scheduleJob (déclencheurs); 32 / * 33 * 6秒钟后关闭 34 * / 35 Thread.sleep (6_000); 36 scheduler.shutdown (); 37 } 38 39 40 @DisallowConcurrentExecution 41 @data 42 publiques statiques classe RejectConcurrentJob outils emploi { 43 privé nom de chaîne; 44 45 @Override 46 publics vide execute (contexte JobExecutionContext) { 47 try { 48 System.out.printf ( "i am% s \ n" , nom); 49 Thread.sleep (2_000); 50 } catch (InterruptedException e) { 51 e.printStackTrace (); 52 } 53 } 54 } 55 }
Principe 3 Éviter l'exploration simultanée
Trouvons JobStore classe de mise en œuvre, dans ce cas RAMJobStore, le point dans la méthode org.quartz.simpl.RAMJobStore # acquireNextTriggers, vous pouvez voir un morceau de cette méthode:
En présence ou l' absence de la classe d'emploi DisallowConcurrentExecution annotation, si elle est présente, est rejetée exécuter simultanément méthode. Si vous appelez le déclencheur à exécuter avec des objets JobDetail, le déclencheur en cours dans la liste d'attente.
Après une exécution en cours de déclenchement est terminée, la liste d' attente pour revenir ajouter à nouveau la gâchette RAMJobStore tenu par, en attendant un prochain appel arrive.