如何中断正在执行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

你可能感兴趣的:(quartz)