Java/Threads/Scheduling
Содержание
Executes a task with a specified timeout
/*
* $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/>.
*
*/
/**
* <p>
* Executes a task with a specified timeout.
* </p>
* @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() {
}
/**
* Executes <code>task</code>. Waits for <code>timeout</code>
* 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();
}
}
/**
* Executes <code>task</code> 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() {
}
}
}
Job Scheduler
/*
*
* 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);
}
}
Runs multiple jobs in parallel
/*
* 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.
* <p>
* 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:
* <pre>
* for (int i=0; i<10; i++){
* System.out.println("Hello World " + i);
* }
* System.out.println("done");
* </pre>
* To this:
* <pre>
* 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();
}
}
}
}
Task Scheduling
/*
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);
}
}
}
Timer class used to implement login and query timeouts
// 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
* <code>TimerListener</code>.
*/
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 a <code>TimerRequest</code>.
*
* @param timeout the desired timeout in milliseconds
* @param target the target object; one of <code>SharedSocket</code> or
* <code>TdsCore</code>
* @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 of <code>TimerRequest</code>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 new <code>TimerThread</code> 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 the <code>TimerThread</code> 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 l <code>TimerListener</code> to be notified on timeout
* @return a handle to the timer request, that can later be used with
* <code>cancelTimer</code>
*/
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
* <code>TimerRequest</code> instance)
* @return <code>true</code> 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
* <code>TimerRequest</code> instance)
* @return <code>true</code> 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;
}
}