org.filesys.server.thread.ThreadRequestPool Maven / Gradle / Ivy
Show all versions of jfileserver Show documentation
/*
* Copyright (C) 2006-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see .
*/
package org.filesys.server.thread;
import java.util.List;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import org.filesys.debug.Debug;
/**
* Thread Request Pool Class
*
*
* Thread pool that processes a queue of thread requests.
*
* @author gkspencer
*/
public class ThreadRequestPool {
// Default/minimum/maximum number of worker threads to use
public static final int DefaultWorkerThreads = 25;
public static final int MinimumWorkerThreads = 4;
public static final int MaximumWorkerThreads = 250;
// Initial size of the timed request queue
public static final int TimedQueueInitialSize = 20;
// Interval to sleep when waiting for a request to be queued
private static long WaitForRequestSleep = 24 * 60 * 60000L; // 1 day
// Queue of requests
private ThreadRequestQueue m_queue;
// Queue of timed requests, in time order, and timed request processing thread
private PriorityBlockingQueue m_timedQueue;
// Timed request processor thread
private TimedRequestProcessor m_timedProcessor;
// Worker threads
private ThreadWorker[] m_workers;
// Count of active worker threads
private AtomicInteger m_activeWorkers;
// Debug enable flag
protected boolean m_debug;
protected boolean m_timedDebug;
/**
* Thread Worker Inner Class
*/
protected class ThreadWorker implements Runnable {
// Worker thread
private Thread mi_thread;
// Shutdown flag
private boolean mi_shutdown = false;
/**
* Class constructor
*
* @param name String
*/
public ThreadWorker(String name) {
// Create the worker thread
mi_thread = new Thread(this);
mi_thread.setName(name);
mi_thread.setDaemon(true);
mi_thread.start();
}
/**
* Request the worker thread to shut down
*/
public final void shutdownRequest() {
mi_shutdown = true;
try {
mi_thread.interrupt();
}
catch (Exception ex) {
}
}
/**
* Run the thread
*/
public void run() {
// Loop until shutdown
ThreadRequest threadReq = null;
while (mi_shutdown == false) {
try {
// Wait for a request to be queued
threadReq = m_queue.removeRequest();
}
catch (InterruptedException ex) {
// Check for shutdown
if (mi_shutdown == true)
break;
}
catch (Throwable ex2) {
ex2.printStackTrace();
}
// If the request is valid process it
if (threadReq != null) {
// DEBUG
if (hasDebug())
Debug.println("Worker " + Thread.currentThread().getName() + ": Req=" + threadReq);
try {
// Update the active worker thread counter
m_activeWorkers.incrementAndGet();
// Process the request
threadReq.runRequest();
}
catch (Throwable ex) {
// Do not display errors if shutting down
if (mi_shutdown == false) {
Debug.println("Worker " + Thread.currentThread().getName() + ":");
Debug.println(ex);
}
}
finally {
// Update the active worker thread counter
m_activeWorkers.decrementAndGet();
}
}
}
}
}
;
/**
* Timed Request Processor Thread Inner Class
*/
protected class TimedRequestProcessor implements Runnable {
// Processor thread
private Thread mi_thread;
// Shutdown flag
private boolean mi_shutdown = false;
/**
* Class constructor
*/
public TimedRequestProcessor() {
// Create the worker thread
mi_thread = new Thread(this);
mi_thread.setName("TimedRequestProcessor");
mi_thread.setDaemon(true);
mi_thread.start();
}
/**
* Request the worker thread to shut down
*/
public final void shutdownRequest() {
mi_shutdown = true;
try {
mi_thread.interrupt();
}
catch (Exception ex) {
}
}
/**
* Run the thread
*/
public void run() {
// Loop until shutdown
while (mi_shutdown == false) {
try {
// Sleep until the first queued event is due to be run, or sleep until a request is queued
if (m_timedQueue.size() == 0) {
// DEBUG
if (hasTimedDebug())
Debug.println("Waiting for timed request ...");
// Sleep until a request is queued
Thread.sleep(WaitForRequestSleep);
} else {
// Determine when the head of the queue request is due to run, sleep for the required time
TimedThreadRequest queueHead = m_timedQueue.peek();
if (queueHead != null) {
// Check if the queue only contains paused requests
if (queueHead.isPaused() == false) {
// Calculate the time to sleep until the request is due to run
long sleepTime = queueHead.getRunAtTime() - System.currentTimeMillis();
if (sleepTime > 0) {
// DEBUG
if (hasTimedDebug())
Debug.println("Next timed request due in " + sleepTime + "ms ...");
// Sleep until the request is due to run
Thread.sleep(sleepTime);
}
// Remove the head of the timed request queue and pass the request to the thread pool for
// processing
queueHead = m_timedQueue.poll();
if (queueHead != null) {
// DEBUG
if (hasTimedDebug())
Debug.println("Passing timed request to thread pool - " + queueHead + ", queue size = " + m_timedQueue.size());
// Pass the request to the thread pool for processing
queueRequest(queueHead);
}
} else {
// DEBUG
if (hasTimedDebug() && m_timedQueue != null)
Debug.println("Waiting for timed request, none active (" + m_timedQueue.size() + ") ...");
// No active requests on the queue, sleep until an active request is queued or existing request becomes active
Thread.sleep(WaitForRequestSleep);
}
}
}
}
catch (InterruptedException ex) {
// Check for shutdown
if (mi_shutdown == true)
break;
}
catch (Throwable ex2) {
Debug.println(ex2);
}
}
}
/**
* Wake up the processor thread to reset the sleep timer
*/
public final void wakeupProcessor() {
mi_thread.interrupt();
}
}
;
/**
* Class constructor
*
* @param threadName String
*/
public ThreadRequestPool(String threadName) {
this(threadName, DefaultWorkerThreads);
}
/**
* Class constructor
*
* @param threadName String
* @param poolSize int
*/
public ThreadRequestPool(String threadName, int poolSize) {
// Create the request queue
m_queue = new ThreadRequestQueue();
// Create the timed request queue
m_timedQueue = new PriorityBlockingQueue(TimedQueueInitialSize);
// Check that we have at least minimum worker threads
if (poolSize < MinimumWorkerThreads)
poolSize = MinimumWorkerThreads;
// Create the worker threads
m_activeWorkers = new AtomicInteger();
m_workers = new ThreadWorker[poolSize];
for (int i = 0; i < m_workers.length; i++)
m_workers[i] = new ThreadWorker(threadName + (i + 1));
// Create the timed request processor
m_timedProcessor = new TimedRequestProcessor();
}
/**
* Check if debug output is enabled
*
* @return boolean
*/
public final boolean hasDebug() {
return m_debug;
}
/**
* Check if timed request debugging is enabled
*
* @return boolean
*/
public final boolean hasTimedDebug() {
return m_timedDebug;
}
/**
* Return the number of requests in the queue
*
* @return int
*/
public final int numberOfRequests() {
return m_queue.numberOfRequests();
}
/**
* Return the number of worker threads in the pool
*
* @return int
*/
public final int numberOfWorkerThreads() { return m_workers.length; }
/**
* Return the number of currently active worker threads
*
* @return int
*/
public final int numberOfActiveThreads() { return m_activeWorkers.get(); }
/**
* Queue a request to the thread pool for processing
*
* @param req ThreadRequest
*/
public final void queueRequest(ThreadRequest req) {
m_queue.addRequest(req);
}
/**
* Queue a number of requests to the thread pool for processing
*
* @param reqList List of thread requests
*/
public final void queueRequests(List reqList) {
m_queue.addRequests(reqList);
}
/**
* Queue a timed request to the thread pool for processing at a particular time
*
* @param timedReq TimedThreadRequest
*/
public final void queueTimedRequest(TimedThreadRequest timedReq) {
// Check if the request is already associated with the thread pool, it might be a requeue
if (timedReq.hasThreadRequestPool()) {
// Remove the request from the thread pool before requeueing it
boolean wasRemoved = timedReq.getThreadRequestPool().removeTimedRequest(timedReq);
// DEBUG
if (hasTimedDebug())
Debug.println("Removed timed request " + timedReq + ", removed=" + wasRemoved);
}
// Add, or requeue, the request
synchronized (m_timedQueue) {
// Get the current head of the timed request queue, may be null
TimedThreadRequest queueHead = m_timedQueue.peek();
// Add the new request to the queue
m_timedQueue.add(timedReq);
timedReq.setThreadRequestPool(this);
// DEBUG
if (hasTimedDebug()) {
Debug.println("Queued timed request " + timedReq);
Debug.println(" Queue=" + m_timedQueue);
}
// Check if the queue was empty or the request is the new head of the queue
if (queueHead == null || timedReq.compareTo(queueHead) == -1) {
// DEBUG
if (hasTimedDebug())
Debug.println("New head of timed request queue, waking processor thread ...");
// Wakeup the timed request processor thread to reset the sleep time, the new
// request is the head of the queue
m_timedProcessor.wakeupProcessor();
}
}
}
/**
* Remove a timed request from the queue
*
* @param timedReq TimedThreadRequest
* @return boolean
*/
public final boolean removeTimedRequest(TimedThreadRequest timedReq) {
boolean wasRemoved = false;
synchronized (m_timedQueue) {
// Remove the timed thread request
wasRemoved = m_timedQueue.remove(timedReq);
timedReq.setThreadRequestPool(null);
}
// Return the remove status
return wasRemoved;
}
/**
* Shutdown the thread pool and release all resources
*/
public void shutdownThreadPool() {
// Shutdown the worker threads
if (m_workers != null) {
for (int i = 0; i < m_workers.length; i++)
m_workers[i].shutdownRequest();
}
// Shutdown the timed request handler
if (m_timedProcessor != null)
m_timedProcessor.shutdownRequest();
}
/**
* Enable/disable debug output
*
* @param ena boolean
*/
public final void setDebug(boolean ena) {
m_debug = ena;
}
/**
* Enable/disable timed request debug output
*
* @param ena boolean
*/
public final void setTimedDebug(boolean ena) {
m_timedDebug = ena;
}
}