ch.randelshofer.quaqua.util.ConcurrentDispatcher Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of Quaqua Show documentation
Show all versions of Quaqua Show documentation
A Mavenisation of the Quaqua Mac OSX Swing Look and Feel (Java library)
Quaqua Look and Feel (C) 2003-2010, Werner Randelshofer.
Mavenisation by Matt Gumbley, DevZendo.org - for problems with
Mavenisation, see Matt; for issues with Quaqua, see the Quaqua home page.
For full license details, see http://randelshofer.ch/quaqua/license.html
The newest version!
/*
* @(#)ConcurrentDispatcher.java 2.1 2009-06-01
*
* Copyright (c) 2002-2010 Werner Randelshofer
* Hausmatt 10, Immensee, CH-6405, Switzerland
* All rights reserved.
*
* You may not use, copy or modify this file, except in compliance with the
* license agreement you entered into with Werner Randelshofer.
* For details see accompanying license terms.
*/
package ch.randelshofer.quaqua.util;
import java.util.*;
import javax.swing.*;
/**
* Processes Runnable objects concurrently on a pool of processor threads.
* The order in which the runnable objects are processed is not
* necesseraly the same in which they were added to the dispatcher.
* There is one thread pool per instance.
*
* Design pattern used: Acceptor
* Role in design pattern: EventCollector and EventProcessor
*
* Example
*
The following program prints "Hello World" on the
* processor thread:
*
* // Create the Dispatcher.
* ConcurrentDispatcher dispatcher = new ConcurrentDispatcher();
*
* // Create the Runnable object.
* Runnable runner = new Runnable() {
* public void run() {
* System.out.println("Hello World");
* }
* };
*
* // Execute the Runnable objekt using the dispatcher.
* dispatcher.dispatch(runner);
*
*
* @author Werner Randelshofer, Hausmatt 10, Immensee, CH-6405, Switzerland
* @version 2.1 2009-06-01 Added dispose method.
*
2.0 2002-04-07 dispatchLIFO added.
*
1.0 2002-05-18 Created.
*/
public class ConcurrentDispatcher {
/**
* The priority of the processor thread.
*/
private int priority;
/**
* The queue stores the events until they
* can be processed by a processor thread.
*/
private final LinkedList queue = new LinkedList();
/**
* Number of concurrent threads.
*/
private int threadCount;
/**
* Maximum number of concurrent threads.
*/
private int maxThreadCount;
/**
* Set the policy to enqueue the runnable
* for later execution if there are no available
* threads in the pool.
*/
public static final int ENQUEUE_WHEN_BLOCKED = 0;
/**
* Set the policy for blocked execution to be that
* the current thread executes the command if there
* are no available threads in the pool.
*/
public static final int RUN_WHEN_BLOCKED = 1;
/**
* The policy used when the maximal number of
* threads is reached.
*/
private int blockingPolicy = ENQUEUE_WHEN_BLOCKED;
/**
* Creates a new ConcurrentDispatcher and
* sets the priority of the processor thread to
* java.lang.Thread.NORM_PRIORITY and with
* up to five concurrent threads in the thread
* pool.
*/
public ConcurrentDispatcher() {
this(Thread.NORM_PRIORITY, 5);
}
/**
* Creates a new ConcurrentDispatcher.
*
* @param priority The priority of the processor
* thread.
* @param maxThreadCount The maximal number of concurrent
* threads in the thread pool.
*/
public ConcurrentDispatcher(int priority, int maxThreadCount) {
this.priority = priority;
this.maxThreadCount = maxThreadCount;
}
/**
* Sets the maximum number of concurrent threads.
* @param maxThreadCount Maximal number of concurrent threads.
* A value of zero or below zero stops the dispatcher
* when the queue is empty.
*/
public void setMaxThreadCount(int maxThreadCount) {
this.maxThreadCount = maxThreadCount;
}
/**
* Returns the maximal number of concurrent threads.
*/
public int getMaxThreadCount() {
return maxThreadCount;
}
/**
* Enqueues the Runnable object, and executes
* it on a processor thread.
*/
public void dispatch(Runnable runner) {
dispatch(runner, false);
}
/**
* Enqueues the Runnable object, and executes
* it on a processor thread.
*/
public void dispatch(Runnable runner, boolean isLIFO) {
isLIFO = false;
synchronized (queue) {
if (threadCount < maxThreadCount) {
if (isLIFO) {
queue.addFirst(runner);
} else {
queue.addLast(runner);
}
Thread processor = new Thread(this + " Processor") {
public void run() {
processEvents();
}
};
threadCount++;
// The processor thread must not be a daemon,
// or else the Java VM might stop before
// all runnables have been processed.
try {
processor.setDaemon(false);
} catch (SecurityException e) {
e.printStackTrace();
}
try {
processor.setPriority(priority);
} catch (SecurityException e) {
e.printStackTrace();
}
processor.start();
return;
} else if (blockingPolicy == ENQUEUE_WHEN_BLOCKED) {
if (isLIFO) {
queue.addFirst(runner);
} else {
queue.addLast(runner);
}
return;
}
}
//implicit: if (threadCount >= maxThreadCount && blockingPolicy == RUN_WHEN_BLOCKED)
runner.run();
}
public void stop() {
}
/**
* This method dequeues all Runnable objects from the
* queue and executes them. The method returns
* when the queue is empty.
*/
protected void processEvents() {
Object runner;
loop:
while (true) {
synchronized (queue) {
if (queue.isEmpty()) {
threadCount--;
break loop;
}
runner = queue.removeFirst();
}
try {
((Runnable) runner).run();
} catch (Throwable e) {
e.printStackTrace();
}
}
}
/**
* Disposes the dispatcher and all associated processes.
*/
public void dispose() {
synchronized (queue) {
queue.clear();
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy