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