Java/Threads/Scheduling

Материал из Java эксперт
Перейти к: навигация, поиск

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() {
   }
   /**
    * Executes task. Waits for timeout
    * 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 task 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 a TimerRequest.
        *
        * @param timeout the desired timeout in milliseconds
        * @param target  the target object; one of SharedSocket 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 of TimerRequests 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 TimerThread 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 TimerThread 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       TimerListener 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)
    * @return true 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)
    * @return true 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>