首页 > 代码库 > 如何中断正在执行IO的 Quartz 作业

如何中断正在执行IO的 Quartz 作业

Interrupt a Quartz job that doing IO

如果你想中断正在执行IO的 Quartz 作业,在你使用 InterruptibleChannel 时这是可行的。引用一下Oracle链接:实现了这个接口的通道,是可中断的:如果一个线程在一个中断通道阻塞I/O操作,另一个线程能调用阻塞的线程的中断方法。这将导致的通道被关闭,被阻塞的线程收到一个ClosedByInterruptException,设置被阻塞的线程的中断状态。因此,获得自己工作的执行线程的作业计划,能保存供以后使用。当Quartz调度中断作业,你可以再调用该线程的interrupt()方法来停止读/写操作。这里有一个简单的例子:

package demo; // import statements excluded for brevity public class MyJob implements InterruptableJob {   private static Logger    LOG              = LoggerFactory.getLogger(MyJob.class);   private volatile boolean isJobInterrupted = false;   private JobKey           jobKey           = null;   private volatile Thread  thisThread;   public MyJob() {  }   public void execute(JobExecutionContext context) throws JobExecutionException {    thisThread = Thread.currentThread();    LOG.info("Thread name of the current job: " + thisThread.getName());     jobKey = context.getJobDetail().getKey();    LOG.info("Job " + jobKey + " executing at " + new Date());     try {      String fileUrl = "http://d2zwv9pap9ylyd.cloudfront.net/terracotta-3.6.1.tar.gz"; // 59 MB      String localFile = "terracotta-3.6.1.tar.gz";      download(fileUrl, localFile);    } catch (ClosedByInterruptException e) {      LOG.info("Caught ClosedByInterruptException... exiting job.");    } catch (IOException e) {      LOG.info("Caught IOException... exiting job.", e);    } finally {      if (isJobInterrupted) {        LOG.info("Job " + jobKey + " did not complete");      } else {        LOG.info("Job " + jobKey + " completed at " + new Date());      }    }  }     // this method is called by the scheduler  public void interrupt() throws UnableToInterruptJobException {    LOG.info("Job " + jobKey + "  -- INTERRUPTING --");    isJobInterrupted = true;    if (thisThread != null) {      // this called cause the ClosedByInterruptException to happen      thisThread.interrupt();    }  }   private void download(String address, String localFileName) throws ClosedByInterruptException, IOException {    URL url = new URL(address);    ReadableByteChannel src = Channels.newChannel(url.openStream());    WritableByteChannel dest = new FileOutputStream(new File(localFileName)).getChannel();    try {      System.out.println("Downloading " + address + " to " + new File(localFileName).getCanonicalPath());      int size = fastChannelCopy(src, dest);      System.out.println("Download completed! " + (size / 1024 / 1024) + " MB");    } finally {      src.close();      dest.close();    }  }     // Code copied from http://thomaswabner.wordpress.com/2007/10/09/fast-stream-copy-using-javanio-channels/  private static int fastChannelCopy(final ReadableByteChannel src, final WritableByteChannel dest) throws IOException {    final ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);    int count = 0;    int total = 0;    while ((count = src.read(buffer)) != -1) {      total += count;      // prepare the buffer to be drained      buffer.flip();      // write to the channel, may block      dest.write(buffer);      // If partial transfer, shift remainder down      // If buffer is empty, same as doing clear()      buffer.compact();    }    // EOF will leave buffer in fill state    buffer.flip();    // make sure the buffer is fully drained.    while (buffer.hasRemaining()) {      dest.write(buffer);    }    return total;  }}

这是我的主类,创建Quartz Scheduler和模拟预期的中断。下载将需要大约40秒完成(59MB文件)。为了看到我们的作业确实是在下载过程中中断,我们启动调度然后休息5秒。注:如果您想看到的作业完成,休息了约40秒。

package demo; import static org.quartz.DateBuilder.nextGivenSecondDate;import static org.quartz.JobBuilder.newJob;import static org.quartz.SimpleScheduleBuilder.simpleSchedule;import static org.quartz.TriggerBuilder.newTrigger; // other imports excluded for brevity public class InterruptExample {   public void run() throws Exception {    final Logger log = LoggerFactory.getLogger(InterruptExample.class);     log.info("------- Initializing ----------------------");     // First we must get a reference to a scheduler    SchedulerFactory sf = new StdSchedulerFactory();    Scheduler sched = sf.getScheduler();     log.info("------- Initialization Complete -----------");     log.info("------- Scheduling Jobs -------------------");     // get a "nice round" time a few seconds in the future...    Date startTime = nextGivenSecondDate(null, 1);     JobDetail job = newJob(MyJob.class).withIdentity("myJob", "group1").build();     SimpleTrigger trigger = newTrigger().withIdentity("trigger1", "group1").startAt(startTime)        .withSchedule(simpleSchedule()).build();     sched.scheduleJob(job, trigger);     // start up the scheduler (jobs do not start to fire until    // the scheduler has been started)    sched.start();    log.info("Scheduler thread‘s name: " + Thread.currentThread().getName());    log.info("------- Started Scheduler -----------------");     try {      // if you want to see the job to finish successfully, sleep for about 40 seconds      Thread.sleep(5 * 1000L);      // tell the scheduler to interrupt our job      sched.interrupt(job.getKey());      Thread.sleep(3 * 1000L);    } catch (Exception e) {      e.printStackTrace();    }     log.info("------- Shutting Down ---------------------");     sched.shutdown(true);     log.info("------- Shutdown Complete -----------------");  }   public static void main(String[] args) throws Exception {    InterruptExample example = new InterruptExample();    example.run();  }}

这是日志,说明我们的作业被intterupted提早退出

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
INFO [main] ------- Initializing ----------------------
INFO [main] Using default implementation for ThreadExecutor
INFO [main] Job execution threads will use class loader of thread: main
INFO [main] Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
INFO [main] Quartz Scheduler v.2.1.3 created.
INFO [main] RAMJobStore initialized.
INFO [main] Scheduler meta-data: Quartz Scheduler (v2.1.3) ‘DefaultQuartzScheduler‘ with instanceId ‘NON_CLUSTERED‘
  Scheduler class: ‘org.quartz.core.QuartzScheduler‘ - running locally.
  NOT STARTED.
  Currently in standby mode.
  Number of jobs executed: 0
  Using thread pool ‘org.quartz.simpl.SimpleThreadPool‘ - with 10 threads.
  Using job-store ‘org.quartz.simpl.RAMJobStore‘ - which does not support persistence. and is not clustered.
 
INFO [main] Quartz scheduler ‘DefaultQuartzScheduler‘ initialized from default resource file in Quartz package: ‘quartz.properties‘
INFO [main] Quartz scheduler version: 2.1.3
INFO [main] ------- Initialization Complete -----------
INFO [main] ------- Scheduling Jobs -------------------
INFO [main] Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.
INFO [main] Scheduler thread‘s name: main
INFO [main] ------- Started Scheduler -----------------
INFO [DefaultQuartzScheduler_Worker-1] Thread name of the current job: DefaultQuartzScheduler_Worker-1
NFO [DefaultQuartzScheduler_Worker-1] Job group1.myJob executing at Mon Apr 16 16:24:40 PDT 2012
 Downloading http://d2zwv9pap9ylyd.cloudfront.net/terracotta-3.6.1.tar.gz to S:\quartz-interrupt-demo\terracotta-3.6.1.tar.gz
INFO [main] Job group1.myJob  -- INTERRUPTING --
INFO [DefaultQuartzScheduler_Worker-1] Caught ClosedByInterruptException... exiting job.
INFO [DefaultQuartzScheduler_Worker-1] Job group1.myJob did not complete
ERROR [DefaultQuartzScheduler_Worker-1] Worker thread was interrupt()‘ed.
 java.lang.InterruptedException
 at java.lang.Object.wait(Native Method)
 at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:552)
INFO [main] ------- Shutting Down ---------------------
INFO [main] Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutting down.
INFO [main] Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED paused.
INFO [main] Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutdown complete.
INFO [main] ------- Shutdown Complete -----------------

原文:http://itindex.net/blog/2012/04/23/1335149680608.html

如何中断正在执行IO的 Quartz 作业