zoukankan      html  css  js  c++  java
  • Java 定时任务 Quartz (三)—— 并发

    1 前言

    根据 Quartz 的设计,一个 Job 可以绑定多个 Trigger,必然会遇到并发的问题。

    2 并发

    2.1 复现

    让我们编写一个并发的例子:

     1 /**
     2  * @author pancc
     3  * @version 1.0
     4  */
     5 public class AcceptConcurrentDemo {
     6 
     7     public static void main(String[] args) throws SchedulerException, InterruptedException {
     8         JobDetail detail = JobBuilder.newJob(AcceptConcurrentJob.class)
     9                 .withIdentity("detail", "group0")
    10                 .build();
    11 
    12 
    13         Trigger trigger = TriggerBuilder.newTrigger()
    14                 .withIdentity("ben_trigger")
    15                 .usingJobData("name", "ben")
    16                 .startNow()
    17                 .build();
    18 
    19         Trigger triggers = TriggerBuilder.newTrigger()
    20                 .withIdentity("mike_trigger")
    21                 .usingJobData("name", "mike")
    22                 .forJob("detail", "group0")
    23                 .startNow()
    24                 .build();
    25 
    26 
    27         Scheduler scheduler = new StdSchedulerFactory().getScheduler();
    28 
    29         scheduler.start();
    30         scheduler.scheduleJob(detail, trigger);
    31         scheduler.scheduleJob(triggers);
    32         /*
    33          * 6 秒钟后关闭
    34          */
    35         Thread.sleep(6_000);
    36         scheduler.shutdown();
    37     }
    38 
    39     @Data
    40     public static class AcceptConcurrentJob implements Job {
    41         private String name;
    42 
    43         @Override
    44         public void execute(JobExecutionContext context) {
    45             try {
    46                 System.out.printf("i am %s 
    ", name);
    47                 Thread.sleep(2_000);
    48             } catch (InterruptedException e) {
    49                 e.printStackTrace();
    50             }
    51         }
    52     }
    53 }

    请注意上边的 Details 的 Identity ,设置为 group0.detail,同时我们创建了两个 Trigger,第二个 trigger 在创建的时候通过指定 Identity 绑定到了目标 Job,接着提交这个 Job,与两个 Trigger ,可以看到两个触发器同时出发了 Job 的 execute 方法

    上边的代码也可以简化为以下形式:

     1 /**
     2  * @author pancc
     3  * @version 1.0
     4  */
     5 public class AcceptConcurrentDemo {
     6 
     7     public static void main(String[] args) throws SchedulerException, InterruptedException {
     8         JobDetail detail = JobBuilder.newJob(AcceptConcurrentJob.class)
     9                 .withIdentity("detail", "group0")
    10                 .build();
    11 
    12 
    13         Trigger trigger = TriggerBuilder.newTrigger()
    14                 .withIdentity("ben_trigger")
    15                 .usingJobData("name", "ben")
    16                 .startNow()
    17                 .build();
    18 
    19         Trigger triggers = TriggerBuilder.newTrigger()
    20                 .withIdentity("mike_trigger")
    21                 .usingJobData("name", "mike")
    22                 .startNow()
    23                 .build();
    24 
    25 
    26         Scheduler scheduler = new StdSchedulerFactory().getScheduler();
    27 
    28         scheduler.start();
    29         scheduler.scheduleJob(detail, Sets.newHashSet(trigger,triggers),true);
    30         /*
    31          * 6 秒钟后关闭
    32          */
    33         Thread.sleep(6_000);
    34         scheduler.shutdown();
    35     }
    36 
    37     @Data
    38     public static class AcceptConcurrentJob implements Job {
    39         private String name;
    40 
    41         @Override
    42         public void execute(JobExecutionContext context) {
    43             try {
    44                 System.out.printf("i am %s 
    ", name);
    45                 Thread.sleep(2_000);
    46             } catch (InterruptedException e) {
    47                 e.printStackTrace();
    48             }
    49         }
    50     }
    51 }

    2.2 避免并发

    为了避免并发,我们可以使用官方提供的注解 @DisallowConcurrentExecution,通过在 类上增加这个注解,我们可以观察到第二个 trigger 进行了排队处理:

     1 /**
     2  * @author pancc
     3  * @version 1.0
     4  */
     5 public class RejectConcurrentDemo {
     6 
     7     public static void main(String[] args) throws SchedulerException, InterruptedException {
     8         JobDetail detail = JobBuilder.newJob(RejectConcurrentJob.class)
     9                 .withIdentity("detail", "group0")
    10                 .build();
    11 
    12 
    13         Trigger trigger = TriggerBuilder.newTrigger()
    14                 .withIdentity("ben_trigger")
    15                 .usingJobData("name", "ben")
    16                 .startNow()
    17                 .build();
    18 
    19         Trigger triggers = TriggerBuilder.newTrigger()
    20                 .withIdentity("mike_trigger")
    21                 .usingJobData("name", "mike")
    22                 .forJob("detail", "group0")
    23                 .startNow()
    24                 .build();
    25 
    26 
    27         Scheduler scheduler = new StdSchedulerFactory().getScheduler();
    28 
    29         scheduler.start();
    30         scheduler.scheduleJob(detail, trigger);
    31         scheduler.scheduleJob(triggers);
    32         /*
    33          * 6 秒钟后关闭
    34          */
    35         Thread.sleep(6_000);
    36         scheduler.shutdown();
    37     }
    38 
    39 
    40     @DisallowConcurrentExecution
    41     @Data
    42     public static class RejectConcurrentJob implements Job {
    43         private String name;
    44 
    45         @Override
    46         public void execute(JobExecutionContext context) {
    47             try {
    48                 System.out.printf("i am %s 
    ", name);
    49                 Thread.sleep(2_000);
    50             } catch (InterruptedException e) {
    51                 e.printStackTrace();
    52             }
    53         }
    54     }
    55 }

    3 避免并发的原理探索

    让我们找到 JobStore 的实现类,在这里是 RAMJobStore,点进去方法 org.quartz.simpl.RAMJobStore#acquireNextTriggers,可以看到这个方法的某个块:

     通过对 Job 类上的是否存在  DisallowConcurrentExecution 注解,如果存在,表示拒绝并发执行 execute 方法。如果与即将执行的 Trigger 调用同一个 JobDetail 对象,则将当前 trigger 放入等待列表。

    之后当前一个 Trigger 执行完毕,将等待中的 Trigger 重新加回去 RAMJobStore 持有的 trigger 列表中,等待下一次调用发生。

  • 相关阅读:
    进程和线程
    关于offer对比
    CVTE面经
    重定向
    奇虎360面试经验
    百纳信息(海豚浏览器)面经
    携程网面经
    百度面经
    位运算
    Cracking the Coding Interview 4.8
  • 原文地址:https://www.cnblogs.com/siweipancc/p/12596241.html
Copyright © 2011-2022 走看看