Java/Threads/Scheduling
Содержание
Executes a task with a specified timeout
<source lang="java">
/*
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/util/TimeoutController.java,v 1.6 2004/04/18 23:51:38 jsdever Exp $ * $Revision: 480424 $ * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $ * * * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */
/**
** Executes a task with a specified timeout. *
* @author Ortwin Glueck * @author * @version $Revision: 480424 $ * @since 2.0 */
public final class TimeoutController {
/** * Do not instantiate objects of this class. Methods are static. */ private TimeoutController() { } /** * Executestask
. Waits fortimeout
* milliseconds for the task to end and returns. If the task does not return * in time, the thread is interrupted and an Exception is thrown. * The caller should override the Thread.interrupt() method to something that * quickly makes the thread die or use Thread.isInterrupted(). * @param task The thread to execute * @param timeout The timeout in milliseconds. 0 means to wait forever. * @throws TimeoutException if the timeout passes and the thread does not return. */ public static void execute(Thread task, long timeout) throws TimeoutException { task.start(); try { task.join(timeout); } catch (InterruptedException e) { /* if somebody interrupts us he knows what he is doing */ } if (task.isAlive()) { task.interrupt(); throw new TimeoutException(); } } /** * Executestask
in a new deamon Thread and waits for the timeout. * @param task The task to execute * @param timeout The timeout in milliseconds. 0 means to wait forever. * @throws TimeoutException if the timeout passes and the thread does not return. */ public static void execute(Runnable task, long timeout) throws TimeoutException { Thread t = new Thread(task, "Timeout guard"); t.setDaemon(true); execute(t, timeout); } /** * Signals that the task timed out. */ public static class TimeoutException extends Exception { /** Create an instance */ public TimeoutException() { } }
}
</source>
Job Scheduler
<source lang="java">
/*
* * Copyright (c) 1997-1999 Scott Oaks and Henry Wong. All Rights Reserved. * * Permission to use, copy, modify, and distribute this software * and its documentation for NON-COMMERCIAL purposes and * without fee is hereby granted. * * This sample source code is provided for example only, * on an unsupported, as-is basis. * * AUTHOR MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. AUTHOR SHALL NOT BE LIABLE FOR * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. * * THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE * CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE * PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT * NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE * SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE * SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE * PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). AUTHOR * SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR * HIGH RISK ACTIVITIES. */
import java.util.*; public class JobScheduler implements Runnable {
final public static int ONCE = 1; final public static int FOREVER = -1; final public static long HOURLY = (long)60*60*1000; final public static long DAILY = 24*HOURLY; final public static long WEEKLY = 7*DAILY; final public static long MONTHLY = -1; final public static long YEARLY = -2; private class JobNode { public Runnable job; public Date executeAt; public long interval; public int count; } private ThreadPool tp; private DaemonLock dlock = new DaemonLock(); private Vector jobs = new Vector(100); public JobScheduler(int poolSize) { tp = (poolSize > 0) ? new ThreadPool(poolSize) : null; Thread js = new Thread(this); js.setDaemon(true); js.start(); } private synchronized void addJob(JobNode job) { dlock.acquire(); jobs.addElement(job); notify(); } private synchronized void deleteJob(Runnable job) { for (int i=0; i < jobs.size(); i++) { if (((JobNode) jobs.elementAt(i)).job == job) { jobs.removeElementAt(i); dlock.release(); break; } } } private JobNode updateJobNode(JobNode jn) { Calendar cal = Calendar.getInstance(); cal.setTime(jn.executeAt); if (jn.interval == MONTHLY) { // There is a minor bug. (see java.util.calendar) cal.add(Calendar.MONTH, 1); jn.executeAt = cal.getTime(); } else if (jn.interval == YEARLY) { cal.add(Calendar.YEAR, 1); jn.executeAt = cal.getTime(); } else { jn.executeAt = new Date(jn.executeAt.getTime() + jn.interval); } jn.count = (jn.count == FOREVER) ? FOREVER : jn.count - 1; return (jn.count != 0) ? jn : null; } private synchronized long runJobs() { long minDiff = Long.MAX_VALUE; long now = System.currentTimeMillis(); for (int i=0; i < jobs.size();) { JobNode jn = (JobNode) jobs.elementAt(i); if (jn.executeAt.getTime() <= now) { if (tp != null) { tp.addRequest(jn.job); } else { Thread jt = new Thread(jn.job); jt.setDaemon(false); jt.start(); } if (updateJobNode(jn) == null) { jobs.removeElementAt(i); dlock.release(); } } else { long diff = jn.executeAt.getTime() - now; minDiff = Math.min(diff, minDiff); i++; } } return minDiff; } public synchronized void run() { while (true) { long waitTime = runJobs(); try { wait(waitTime); } catch (Exception e) {}; } } public void execute(Runnable job) { executeIn(job, (long)0); } public void executeIn(Runnable job, long millis) { executeInAndRepeat(job, millis, 1000, ONCE); } public void executeInAndRepeat(Runnable job, long millis, long repeat) { executeInAndRepeat(job, millis, repeat, FOREVER); } public void executeInAndRepeat(Runnable job, long millis, long repeat, int count) { Date when = new Date(System.currentTimeMillis() + millis); executeAtAndRepeat(job, when, repeat, count); } public void executeAt(Runnable job, Date when) { executeAtAndRepeat(job, when, 1000, ONCE); } public void executeAtAndRepeat(Runnable job, Date when, long repeat) { executeAtAndRepeat(job, when, repeat, FOREVER); } public void executeAtAndRepeat(Runnable job, Date when, long repeat, int count) { JobNode jn = new JobNode(); jn.job = job; jn.executeAt = when; jn.interval = repeat; jn.count = count; addJob(jn); } public void cancel(Runnable job) { deleteJob(job); } public void executeAtNextDOW(Runnable job, Date when, int DOW) { Calendar target = Calendar.getInstance(); target.setTime(when); while (target.get(Calendar.DAY_OF_WEEK) != DOW) target.add(Calendar.DATE, 1); executeAt(job, target.getTime()); } public void configureBackup(Runnable job) { Calendar now = Calendar.getInstance(); executeAtNextDOW(job, now.getTime(), Calendar.SUNDAY); } public static void main(String[] args) throws Exception { Runnable r1 = new Runnable() { public void run() { System.out.print("1"); try { Thread.sleep(5000); } catch (Exception ex) {}; System.out.print("1"); } }; Runnable r2 = new Runnable() { public void run() { System.out.print("2"); try { Thread.sleep(5000); } catch (Exception ex) {}; System.out.print("2"); } }; Runnable r3 = new Runnable() { public void run() { System.out.print("3"); } }; Runnable r4 = new Runnable() { public void run() { System.out.print("4"); } }; JobScheduler js = new JobScheduler(0); Thread.sleep(1000); // Test 1 - General Test js.executeInAndRepeat(r1, 10000, 3000, 10); js.executeInAndRepeat(r2, 20000, 1000, 10); //Thread.sleep(11000); //js.cancel(r1); //js.cancel(r2); //js.configureBackup(r1); // Test 2 - Signature Test //Date in10Sec = new Date(System.currentTimeMillis()+10000L); //js.execute(r1); //js.executeIn(r2, 2000L); //js.executeInAndRepeat(r3, 10000L, 2000L); //js.executeInAndRepeat(r4, 10000L, 2000L, 5); //js.executeAt(r1, in10Sec); //js.executeAtAndRepeat(r2, in10Sec, 2000L); //js.executeAtAndRepeat(r3, in10Sec, 1000L, 5); //js.cancel(r4); //Thread.sleep(20000L); //js.cancel(r2); // Test 3 - Interval Test //js.executeInAndRepeat(r3, 10000L, JobScheduler.HOURLY); //js.executeInAndRepeat(r3, 10000L, JobScheduler.DAILY); //js.executeInAndRepeat(r3, 10000L, JobScheduler.WEEKLY); //js.executeInAndRepeat(r3, 10000L, JobScheduler.MONTHLY); //js.executeInAndRepeat(r3, 10000L, JobScheduler.YEARLY); }
}
</source>
Runs multiple jobs in parallel
<source lang="java">
/*
* Runs multiple jobs in parallel * Copyright (C) 2004-2005 Matt Conway * http://simplygenius.ru/ * Copyright (C) 2005 Stephen Ostermiller * http://ostermiller.org/contact.pl?regarding=Java+Utilities * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * See COPYING.TXT for details. */
import java.util.*; /**
* Runs multiple jobs in parallel, n threads at a time, and waits * until all threads are complete before continuing.*
* Typically, Parallelizer would be used to run each of the items- * in a for loop at the same time. For example the following for * loop: *
* for (int i=0; i<10; i++){ * System.out.println("Hello World " + i); * } * System.out.println("done"); *
* To this:*
* Parallelizer parallelizer = new Parallelizer(); * for (int i=0; i<10; i++){ * final int j = i; * parallelizer.run( * new Runnable(){ * System.out.println("Hello World " + j); * } * ); * } * parallelizer.join(); * System.out.println("done"); * * More information about this class is available from . * * @author Matt Conway - http://simplygenius.ru/ * @author Stephen Ostermiller - http://ostermiller.org/contact.pl?regarding=Java+Utilities * @since ostermillerutils 1.05.00 */ public class Parallelizer { /** * Constant that may be passed concurrentThreadLimit argument * of the constructor indicating that no limit should be placed * on the number of threads that are allowed to run concurrently. * * @since ostermillerutils 1.05.00 */ public static final int INFINITE_THREAD_LIMIT = 0; /** * The number of threads that are allowed to be run concurrently. * (INFINITE_THREAD_LIMIT for no limit) */ private int concurrentThreadLimit = INFINITE_THREAD_LIMIT; /** * Create a new Parallelizer with no limit on the number * of threads that will be allowed to be run concurrently. * * @since ostermillerutils 1.05.00 */ public Parallelizer(){ this(INFINITE_THREAD_LIMIT); } /** * Create a new Parallelizer with the specified limit on the number * of threads that will be allowed to be run concurrently. * <p> * When the concurrent thread limit is reached and the parallelizer * gets a new thread to run, the new thread will be queued until * a thread finishes. * * @param concurrentThreadLimit number of threads that will be allowed * to run simultaneously or INFINITE_THREAD_LIMIT for no limit. * @throws IllegalArgumentException if concurrentThreadLimit not a whole * number or INFINITE_THREAD_LIMIT * * @since ostermillerutils 1.05.00 */ public Parallelizer(int concurrentThreadLimit){ if (concurrentThreadLimit < INFINITE_THREAD_LIMIT) throw new IllegalArgumentException("Bad concurrent thread limit: " + concurrentThreadLimit); this.concurrentThreadLimit = concurrentThreadLimit; } /** * A Set of threads that are currently running. * This set is also used as a lock to synchronize * anything that touches running threads. */ private HashSet<Thread> runningThreads = new HashSet<Thread>(); /** * A queue of jobs that have not yet been started. */ private LinkedList<Thread> toRunQueue = new LinkedList<Thread>(); /** * Run the given job. The given job is either run * immediately or if the max number of concurrent jobs are already * running, it is queued to be run when some job is finished. * <p> * If this method throws an error, that * error may be handled and this method * may be called again as it will not re-throw the same * instance of the error. * * @param job job which is to be run in parallel with other jobs. * @throws Error if any thread that is already running has thrown an Error. * @throws NullPointerException if job is null. * * @since ostermillerutils 1.05.00 */ public void run(Runnable job){ run(null, job, null, 0); } /** * Run the given job. The given job is either run * immediately or if the max number of concurrent jobs are already * running, it is queued to be run when some job is finished. * <p> * If this method throws an error, that * error may be handled and this method * may be called again as it will not re-throw the same * instance of the error. * * @param job job which is to be run in parallel with other jobs. * @param threadName name for the thread that will be created to run the job (null for auto generated thread name) * @throws Error if any thread that is already running has thrown an Error. * @throws NullPointerException if job is null. * * @since ostermillerutils 1.05.00 */ public void run(Runnable job, String threadName){ run(null, job, threadName, 0); } /** * Run the given job. The given job is either run * immediately or if the max number of concurrent jobs are already * running, it is queued to be run when some job is finished. * <p> * If this method throws an error, that * error may be handled and this method * may be called again as it will not re-throw the same * instance of the error. * * @param threadGroup group in which this job should be run (null for default group). * @param job job which is to be run in parallel with other jobs. * @throws Error if any thread that is already running has thrown an Error. * @throws NullPointerException if job is null. * * @since ostermillerutils 1.05.00 */ public void run(ThreadGroup threadGroup, Runnable job){ run(threadGroup, job, null, 0); } /** * Run the given job. The given job is either run * immediately or if the max number of concurrent jobs are already * running, it is queued to be run when some job is finished. * <p> * If this method throws an error, that * error may be handled and this method * may be called again as it will not re-throw the same * instance of the error. * * @param threadGroup group in which this job should be run (null for default group). * @param job job which is to be run in parallel with other jobs. * @param threadName name for the thread that will be created to run the job (null for auto generated thread name) * @throws Error if any thread that is already running has thrown an Error. * @throws NullPointerException if job is null. * * @since ostermillerutils 1.05.00 */ public void run(ThreadGroup threadGroup, Runnable job, String threadName){ run(threadGroup, job, threadName, 0); } /** * Run the given job. The given job is either run * immediately or if the max number of concurrent jobs are already * running, it is queued to be run when some job is finished. * <p> * If this method throws an error, that * error may be handled and this method * may be called again as it will not re-throw the same * instance of the error. * * @param threadGroup group in which this job should be run (null for default group). * @param job job which is to be run in parallel with other jobs. * @param threadName name for the thread that will be created to run the job (null for auto generated thread name) * @param stackSize system dependent stack size suggestion for thread creation (0 for default stack size). * @throws Error if any thread that is already running has thrown an Error. * @throws NullPointerException if job is null. * * @since ostermillerutils 1.05.00 */ public void run(ThreadGroup threadGroup, final Runnable job, String threadName, long stackSize){ throwFirstError(); Runnable jobWrapper = new Runnable(){ public void run(){ try { job.run(); } catch (RuntimeException runtimeException){ // Put exceptions in the exception queue synchronized(runningThreads){ exceptionList.add(runtimeException); } } catch (Error error){ // Put errors in the error queue synchronized(runningThreads){ errorList.add(error); } } finally { synchronized(runningThreads){ // when done remove ourselves from the list // of running threads. runningThreads.remove(Thread.currentThread()); // Notify the block method. runningThreads.notifyAll(); } // If there are jobs queued up to be run, now would // be a good time to run them. startAJobIfNeeded(); } } }; // ensure the thread name is not null, and auto generate a name if it is threadName = getNextThreadName(threadName); // If we are already running the max number of jobs, queue this job up synchronized(runningThreads){ toRunQueue.add( new Thread( threadGroup, jobWrapper, threadName, stackSize ) ); } // Now that the job is in the queue of jobs to run, // check the queue and see if the job should be started startAJobIfNeeded(); } /** * An number to assign to the next auto generated thread name */ private static int threadNameCount = 0; /** * Ensure the given thread name is not null. If not null, return it, * if it is null, then then generate a name. * * @param threadName existing thread name to check * @return the given thread name or a generated thread name if the specified name was null. */ private static String getNextThreadName(String threadName){ if (threadName != null) return threadName; return "Parallelizer-"+(threadNameCount++); } /** * A queue of exceptions that running threads have thrown. */ private LinkedList<RuntimeException> exceptionList = new LinkedList<RuntimeException>(); /** * Remove the first exception from the exception list and throw it. * * @throws RuntimeException if a running thread has thrown an exception not yet thrown by this method. */ private void throwFirstException(){ synchronized(runningThreads){ if (exceptionList.size() > 0){ throw exceptionList.removeFirst(); } } } /** * A queue of exceptions that running threads have thrown. */ private LinkedList<Error> errorList = new LinkedList<Error>(); /** * Remove the first error from the error list and throw it. * * @throws Error if a running thread has thrown an error not yet thrown by this method. */ private void throwFirstError() throws Error { synchronized(runningThreads){ if (errorList.size() > 0){ throw errorList.removeFirst(); } } } /** * Remove a job from the toRunQueue, create a thread for it, * start the thread, and put the job in the set of running jobs. * But do all this only if there are jobs queued up to be run * and we are not already running the max number of concurrent * jobs at once. */ private void startAJobIfNeeded(){ synchronized(runningThreads){ // If we are already running the max number of jobs, just return if (concurrentThreadLimit != INFINITE_THREAD_LIMIT){ if (runningThreads.size() >= concurrentThreadLimit) return; } // If there are no more job to run, return if (toRunQueue.size() == 0) return; // Get a job out of the queue Thread thread = toRunQueue.removeFirst(); // Put the thread in the list of running threads runningThreads.add(thread); thread.start(); } } /** * Return true iff all jobs that have been requested to run * in this Parallelizer have completed. * <p> * If this method throws an error, that * error may be handled and this method * may be called again as it will not re-throw the same * instance of the error. * * @return Whether all jobs are done or not. * @throws Error if any of the running threads has thrown an Error. * * @since ostermillerutils 1.05.00 */ public boolean done(){ throwFirstError(); synchronized(runningThreads){ return (toRunQueue.size() + runningThreads.size()) == 0; } } /** * All currently running threads will be interrupted. * The threads interrupted threads may die, causing * jobs that were queued but not yet started, to start. * <p> * If this method throws an error, that * error may be handled and this method * may be called again as it will not re-throw the same * instance of the error. * * @throws Error if any of the running threads has thrown an Error. * * @since ostermillerutils 1.05.00 */ public void interrupt(){ throwFirstError(); synchronized(runningThreads){ for (Thread thread: runningThreads) { (thread).interrupt(); throwFirstError(); } } } /** * Dump the stack of each running thread. * <p> * If this method throws an error, that * error may be handled and this method * may be called again as it will not re-throw the same * instance of the error. * * @throws Error if any of the running threads has thrown an Error. * * @since ostermillerutils 1.05.00 */ public void dumpStack(){ throwFirstError(); synchronized(runningThreads){ for (Thread thread: runningThreads) { for (StackTraceElement stackTraceElement: thread.getStackTrace()){ System.out.println(stackTraceElement.toString()); } throwFirstError(); } } } /** * Gets a list of all running threads. There may be jobs that * are queued and do not yet have threads. These job are not * returned. * <p> * If this method throws an error, that * error may be handled and this method * may be called again as it will not re-throw the same * instance of the error. * * @throws Error if any of the running threads has thrown an Error. * @return an array of all currently running threads. * * @since ostermillerutils 1.05.00 */ public Thread[] getRunningThreads(){ throwFirstError(); synchronized(runningThreads){ return runningThreads.toArray(new Thread[0]); } } /** * Block until all the jobs in this Parallelizer have run * and then return. * <p> * If this method throws an exception or an error, that * exception or error may be handled and this method * may be called again as it will not re-throw the same * instance of the exception or error. * * @throws InterruptedException if interrupted while waiting. * @throws RuntimeException any running thread throws or has thrown a runtime exception. * @throws Error if any of the running threads throws or has thrown an Error. * * @since ostermillerutils 1.05.00 */ public void join() throws InterruptedException { while (!done()){ synchronized(runningThreads){ throwFirstException(); runningThreads.wait(); throwFirstError(); throwFirstException(); } } } } </source>Task Scheduling
<source lang="java">/* Java Threads, 3rd Edition By Scott Oaks, Henry Wong 3rd Edition September 2004 ISBN: 0-596-00782-5
- /
import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.Timer; import java.util.TimerTask; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.SwingUtilities; public class URLMonitorPanel extends JPanel implements URLPingTask.URLUpdate {
Timer timer; URL url; URLPingTask task; JPanel status; JButton startButton, stopButton; public URLMonitorPanel(String url, Timer t) throws MalformedURLException { setLayout(new BorderLayout()); timer = t; this.url = new URL(url); add(new JLabel(url), BorderLayout.CENTER); JPanel temp = new JPanel(); status = new JPanel(); status.setSize(20, 20); temp.add(status); startButton = new JButton("Start"); startButton.setEnabled(false); startButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { makeTask(); startButton.setEnabled(false); stopButton.setEnabled(true); } }); stopButton = new JButton("Stop"); stopButton.setEnabled(true); stopButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { task.cancel(); startButton.setEnabled(true); stopButton.setEnabled(false); } }); temp.add(startButton); temp.add(stopButton); add(temp, BorderLayout.EAST); makeTask(); } private void makeTask() { task = new URLPingTask(url, this); timer.schedule(task, 0L, 5000L); } public void isAlive(final boolean b) { SwingUtilities.invokeLater(new Runnable() { public void run() { status.setBackground(b ? Color.GREEN : Color.RED); status.repaint(); } }); } public static void main(String[] args) throws Exception { JFrame frame = new JFrame("URL Monitor"); Container c = frame.getContentPane(); c.setLayout(new BoxLayout(c, BoxLayout.Y_AXIS)); Timer t = new Timer(); String[] u = new String[]{"http://www.jexp.ru","http://www.jexp.ru"}; for (int i = 0; i < u.length; i++) { c.add(new URLMonitorPanel(u[i], t)); } frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent evt) { System.exit(0); } }); frame.pack(); frame.show(); }
} class URLPingTask extends TimerTask {
public interface URLUpdate { public void isAlive(boolean b); } URL url; URLUpdate updater; public URLPingTask(URL url) { this(url, null); } public URLPingTask(URL url, URLUpdate uu) { this.url = url; updater = uu; } public void run() { if (System.currentTimeMillis() - scheduledExecutionTime() > 5000) { // Let the next task do it return; } try { HttpURLConnection huc = (HttpURLConnection) url.openConnection(); huc.setConnectTimeout(1000); huc.setReadTimeout(1000); int code = huc.getResponseCode(); if (updater != null) updater.isAlive(true); } catch (Exception e) { if (updater != null) updater.isAlive(false); } }
}
</source>
Timer class used to implement login and query timeouts
<source lang="java">
// jTDS JDBC Driver for Microsoft SQL Server and Sybase // Copyright (C) 2004 The jTDS Project // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // import java.util.LinkedList; import java.util.ListIterator; /**
* Simple timer class used to implement login and query timeouts. * <p/> * This thread runs as a Daemon thread to ensure that the java VM will exit * correctly when normal execution is complete. * <p/> * It provides both a singleton implementation and a default constructor for * the case when more than one timer thread is desired. * * @author Alin Sinpalean * @author Mike Hutchinson * @version $Id: TimerThread.java,v 1.5 2005/04/28 14:29:31 alin_sinpalean Exp $ */
public class TimerThread extends Thread {
/** * Interface to be implemented by classes that request timer services. */ public interface TimerListener { /** * Event to be fired when the timeout expires. */ void timerExpired(); } /** * Internal class associating a login or query timeout value with a target *TimerListener
. */ private static class TimerRequest { /** The time when this timeout will expire. */ final long time; /** Target to notify when the timeout expires. */ final TimerListener target; /** * Create aTimerRequest
. * * @param timeout the desired timeout in milliseconds * @param target the target object; one ofSharedSocket
or *TdsCore
* @throws IllegalArgumentException if the timeout is negative or 0 */ TimerRequest(int timeout, TimerListener target) { if (timeout <= 0) { throw new IllegalArgumentException("Invalid timeout parameter " + timeout); } this.time = System.currentTimeMillis() + (timeout); this.target = target; } } /** Singleton instance. */ private static TimerThread instance; /** List ofTimerRequest
s to execute, ordered by time. */ private final LinkedList timerList = new LinkedList(); /** Time when the first request time out should occur. */ private long nextTimeout; /** * Singleton getter. */ public static synchronized TimerThread getInstance() { if (instance == null) { instance = new TimerThread(); instance.start(); } return instance; } /** * Construct a newTimerThread
instance. */ public TimerThread() { // Set the thread name super("jTDS TimerThread"); // Ensure that this thread does not prevent the VM from exiting this.setDaemon(true); } /** * Execute theTimerThread
main loop. */ public void run() { synchronized (timerList) { while (true) { try { try { // If nextTimeout == 0 (i.e. there are no more requests // in the queue) wait indefinitely -- wait(0) timerList.wait(nextTimeout == 0 ? 0 : nextTimeout - System.currentTimeMillis()); } catch (IllegalArgumentException ex) { // Timeout was negative, fire timeout } // Fire expired timeout requests long time = System.currentTimeMillis(); while (!timerList.isEmpty()) { // Examime the head of the list and see // if the timer has expired. TimerRequest t = (TimerRequest) timerList.getFirst(); if (t.time > time) { break; // No timers have expired } // Notify target of timeout t.target.timerExpired(); // Remove the fired timeout request timerList.removeFirst(); } // Determine next timeout updateNextTimeout(); } catch (InterruptedException e) { // nop } } } } /** * Add a timer request to the queue. * <p/> * The queue is ordered by time so that the head of the list is always the * first timer to expire. * * @param timeout the interval in milliseconds after which the timer will * expire * @param lTimerListener
to be notified on timeout * @return a handle to the timer request, that can later be used with *cancelTimer
*/ public Object setTimer(int timeout, TimerListener l) { // Create a new timer request TimerRequest t = new TimerRequest(timeout, l); synchronized (timerList) { if (timerList.isEmpty()) { // List was empty, just add new request timerList.add(t); } else { // Tiny optimization; new requests will usually go to the end TimerRequest crt = (TimerRequest) timerList.getLast(); if (t.time >= crt.time) { timerList.addLast(t); } else { // Iterate the list and insert it into the right place for (ListIterator li = timerList.listIterator(); li.hasNext(); ) { crt = (TimerRequest) li.next(); if (t.time < crt.time) { li.previous(); li.add(t); break; } } } } // If this request is now the first in the list, interupt timer if (timerList.getFirst() == t) { nextTimeout = t.time; this.interrupt(); } } // Return the created request as timer handle return t; } /** * Remove a redundant timer before it expires. * * @param handle handle to the request to be removed from the queue (a *TimerRequest
instance) * @returntrue
if timer had not expired */ public boolean cancelTimer(Object handle) { TimerRequest t = (TimerRequest) handle; synchronized (timerList) { boolean result = timerList.remove(t); if (nextTimeout == t.time) { updateNextTimeout(); } return result; } } /** * Check whether a timer has expired. * * @param handle handle to the request to be checked for expiry (a *TimerRequest
instance) * @returntrue
if timer has expired */ public boolean hasExpired(Object handle) { TimerRequest t = (TimerRequest) handle; synchronized (timerList) { return !timerList.contains(t); } } /** Internal method that updates the value of {@link #nextTimeout}. */ private void updateNextTimeout() { nextTimeout = timerList.isEmpty() ? 0 : ((TimerRequest) timerList.getFirst()).time; }
}
</source>