Package org.openeai.threadpool

Source Code of org.openeai.threadpool.ThreadPoolImpl$PoolThread

/*******************************************************************************
$Source: /cvs/repositories/openii3/project/java/source/org/openeai/threadpool/ThreadPoolImpl.java,v $
$Revision: 1.5 $
*******************************************************************************/

/**********************************************************************
This file is part of the OpenEAI Application Foundation or
OpenEAI Message Object API created by Tod Jackson
(tod@openeai.org) and Steve Wheat (steve@openeai.org) at
the University of Illinois Urbana-Champaign.

Copyright (C) 2002 The OpenEAI Software Foundation

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

For specific licensing details and examples of how this software
can be used to build commercial integration software or to implement
integrations for your enterprise, visit http://www.OpenEai.org/licensing.
*/

package org.openeai.threadpool;

// Thread Pool implementation class.

import java.util.Vector;
import java.lang.IllegalArgumentException;
import java.lang.NumberFormatException;
import java.lang.InterruptedException;
import java.lang.Thread;
import java.lang.Runnable;
import org.openeai.config.ThreadPoolConfig;

public class ThreadPoolImpl implements ThreadPool {

  // max number of threads that can be created
  private int _maxThreads = -1;

  // min number of threads that must always be present
  private int _minThreads = -1;

  // max idle time after which a thread may be killed
  private int _maxIdleTime = -1;

  // A list i.e. vector of pending jobs
  private Vector _pendingJobs = new Vector();

  // A list i.e. vector of all available threads
  private Vector _availableThreads = new Vector();

  // The debug flag
  private boolean _debug = false;

  private boolean m_shutdown = false;
  private boolean m_checkBeforeProcessing = false;

  // This class represents an element in the available threads vector.
  private class ThreadElement {

    // if true then the thread can process a new job
    private boolean _idle;

    // serves as the key
    private Thread _thread;

    public ThreadElement(Thread thread) {
      _thread = thread;
      _idle = true;
    }
  }

  public boolean checkBeforeProcessing() {
    return m_checkBeforeProcessing;
  }

  // Each thread in the pool is an instance of this class
  private class PoolThread extends Thread {
    private Object _lock;

    // pass in the pool instance for synchronization.
    public PoolThread(Object lock) {
      _lock = lock;
    }

    // This is where all the action is...
    public void run() {
      Runnable job = null;

      while (true) {
        while (true) {
          synchronized(_lock) {
            // Keep processing jobs until none availble
            if (_pendingJobs.size() == 0) {
              if (_debug)
                System.out.println("Idle Thread...");
              int index = findMe();
              if (index == -1)
                return;
              ((ThreadElement)_availableThreads.get(index))._idle = true;
              break;
            }

            // Remove the job from the pending list.
            job = (Runnable)_pendingJobs.firstElement();
            _pendingJobs.removeElementAt(0);
          }

          // run the job
          job.run();
          job = null;
        }

        try {
          synchronized(this) {
            // if no idle time specified, wait till notified.
            if (_maxIdleTime == -1)
              wait();
            else
              wait(_maxIdleTime);
          }
        }
        catch (InterruptedException e) {
          // Cleanup if interrupted
          synchronized(_lock) {
            if (_debug)
              System.out.println("Interrupted...");
            removeMe();
          }
          return;
        }

        // Just been notified or the wait timed out
        synchronized(_lock) {
          // If there are no jobs, that means we "idled" out.
          if (_pendingJobs.size() == 0) {
            if (_minThreads != -1 && _availableThreads.size() > _minThreads) {
              if (_debug)
                System.out.println("Thread timed out...");
              removeMe();
              return;
            }
          }
        }
      }
    }
  }

  public ThreadPoolImpl(ThreadPoolConfig tConfig) throws NumberFormatException, IllegalArgumentException {
    this(tConfig.getProperties());
  }

  public ThreadPoolImpl(java.util.Properties props) throws NumberFormatException, IllegalArgumentException {
    if (props == null)
      return;

    setShutdown(false);

    Object o = props.getProperty("maxThreads");
    if (o != null) {
      int n = java.lang.Integer.parseInt((String)o);
      if (n < 1)
        throw new IllegalArgumentException("maxThreads must be an integral value greater than 0");
      _maxThreads = n;
    }

    o = props.getProperty("minThreads");
    if (o != null) {
      int n = java.lang.Integer.parseInt((String)o);
      if (n < 0)
        throw new IllegalArgumentException("minThreads must be an integral value greater than or equal to 0");
      if (n > _maxThreads)
        throw new IllegalArgumentException("minThreads cannot be greater than maxThreads");
      _minThreads = n;
    }

    o = props.getProperty("maxIdleTime");
    if (o != null) {
      int n = java.lang.Integer.parseInt((String)o);
      if (n < 1)
        throw new IllegalArgumentException("maxIdleTime must be an integral value greater than 0");
      _maxIdleTime = n;
    }

    o = props.getProperty("debug");
    if (o != null) {
      _debug = true;
    }

    m_checkBeforeProcessing = new Boolean(props.getProperty("checkBeforeProcessing","false")).booleanValue();
  }

/**
  * Sets a flag indicating that the ThreadPool is in a 'shutdown' status.  No more jobs can be
  * added to the pool when this happens.
  */
  public void shutdown() {
    setShutdown(true);
  }
  private void setShutdown(boolean sd) {
    m_shutdown = sd;
  }
  private boolean isShutdown() {
    return m_shutdown;
  }
 
  /**
  * Adds a 'job' to the ThreadPool to be executed in a Thread.
  *
  * @param job java.lang.Runnable the job to be added to the ThreadPool
  * @throws - ThreadPoolException if it has any problems adding the job to the ThreadPool.
  **/
  synchronized public void addJob(java.lang.Runnable job) throws ThreadPoolException {

    if (isShutdown()) {
      throw new ThreadPoolException("ThreadPool is shutdown, can't add any jobs.");
    }

    if (m_checkBeforeProcessing) {
      if (getJobsInProgress() >= _maxThreads) {
        throw new ThreadPoolException("All jobs are in progress, can't add any more at this time (" +
          getJobsInProgress() + ") jobs.");
      }
    }

    _pendingJobs.add(job);
    int index = findFirstIdleThread();
    if (index == -1) {
      // All threads are busy

      if (_maxThreads == -1 || _availableThreads.size() < _maxThreads) {
        // We can create another thread...
        if (_debug)
          System.out.println("Creating a new Thread...");
        ThreadElement e = new ThreadElement(new PoolThread(this));
        e._idle = false;
        e._thread.start();
        _availableThreads.add(e);
        return;
      }

      // We are not allowed to create any more threads
      // So, just return.
      // When one of the busy threads is done,
      // it will check the pending queue and will see this job.
      if (_debug)
        System.out.println("Max Threads created and all threads in the pool are busy.");
    }
    else {
      // There is at least one idle thread

      if (_debug)
        System.out.println("Using an existing thread...");
      ((ThreadElement)_availableThreads.get(index))._idle = false;
      synchronized(((ThreadElement)_availableThreads.get(index))._thread) {
        ((ThreadElement)_availableThreads.get(index))._thread.notify();
      }
    }
  }

  synchronized public Stats getStats() {
    Stats stats = new Stats();
    stats.maxThreads = _maxThreads;
    stats.minThreads = _minThreads;
    stats.maxIdleTime = _maxIdleTime;
    stats.pendingJobs = _pendingJobs.size();          
    stats.numThreads = _availableThreads.size();       
    stats.jobsInProgress =
    _availableThreads.size() - findNumIdleThreads();
    stats.check = checkBeforeProcessing();
    return(stats);      
  }

  synchronized public int getJobsInProgress() {
    return _availableThreads.size() - findNumIdleThreads();
  }

  //*****************************************//
  // Important...
  // All private methods must always be
  // called from a synchronized method!!
  //*****************************************//

  // Called by the thread pool to find the number of idle threads
  private int findNumIdleThreads() {
    int idleThreads = 0;
    int size = _availableThreads.size();
    for (int i=0; i<size; i++) {
      if (((ThreadElement)_availableThreads.get(i))._idle)
        idleThreads++;
    }
    return(idleThreads);
  }

  // Called by the thread pool to find the first idle thread
  private int findFirstIdleThread() {
    int size = _availableThreads.size();
    for (int i=0; i<size; i++) {
      if (((ThreadElement)_availableThreads.get(i))._idle)
        return(i);
    }
    return(-1);
  }

  // Called by a pool thread to find itself in the vector of available threads.
  private int findMe() {
    int size = _availableThreads.size();
    for (int i=0; i<size; i++) {
      if (((ThreadElement)_availableThreads.get(i))._thread == Thread.currentThread())
        return(i);
    }
    return(-1);
  }

  // Called by a pool thread to remove itself from the vector of available threads
  private void removeMe() {
    int size = _availableThreads.size();
    for (int i=0; i<size; i++) {
      if (((ThreadElement)_availableThreads.get(i))._thread == Thread.currentThread()) {
        _availableThreads.remove(i);
        return;
      }
    }     
  }
}
TOP

Related Classes of org.openeai.threadpool.ThreadPoolImpl$PoolThread

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.