-// Copyright 2000-2005 the Contributors, as shown in the revision logs.
+// Copyright 2000-2009 the Contributors, as shown in the revision logs.
// Licensed under the Apache Public Source License 2.0 ("the License").
// You may not use this file except in compliance with the License.
* threads exist overall, any threads which complete their task will
* be allowed to die.
*
+ * Locking order: never attempt to acquire a lock on a PooledThread
+ * while holding the ThreadPool lock.
*/
public final class ThreadPool {
public ThreadPool(int minThreads) {
this.minThreads = minThreads;
- this.numThreads = 0;
+ this.numThreads = minThreads;
this.numIdleThreads = 0;
this.idleThreads = new PooledThread[minThreads];
for(int i=0; i<this.idleThreads.length; i++)
new PooledThread();
}
- public synchronized void start(Runnable r) {
- /* if no idle threads, wait for MINIMUM_DISPATCH_DELAY or until notified */
- if (numIdleThreads == 0) try {
- this.wait(MINIMUM_DISPATCH_DELAY);
- } catch (Exception e) { Log.error(this, e); }
-
- /* if there are idle threads, use one */
- if (numIdleThreads > 0) {
- numIdleThreads--;
- idleThreads[numIdleThreads].start(r);
- idleThreads[numIdleThreads] = null;
- return;
+ public void start(Runnable r) {
+ synchronized(ThreadPool.this) {
+ /* if no idle threads, wait for MINIMUM_DISPATCH_DELAY or until notified */
+ if (numIdleThreads == 0) try {
+ this.wait(MINIMUM_DISPATCH_DELAY);
+ } catch (Exception e) { Log.error(this, e); }
+
+ /* if there are idle threads, use one */
+ if (numIdleThreads > 0) {
+ numIdleThreads--;
+ idleThreads[numIdleThreads].start(r);
+ idleThreads[numIdleThreads] = null;
+ return;
+ }
+ /* otherwise, create a new thread */
+ numThreads++;
}
-
- /* otherwise, create a new thread */
new PooledThread().start(r);
}
private class PooledThread extends Thread {
private Runnable runnable = null;
- public PooledThread() {
- synchronized(ThreadPool.this) { numThreads++; }
- start();
- }
- public synchronized void start(Runnable runnable) {
- if (this.runnable != null)
- throw new Error("start() on a thread that is alread busy!");
- this.runnable = runnable;
- notify();
+ public PooledThread() { start(); }
+ void start(Runnable runnable) {
+ synchronized(this) {
+ if (this.runnable != null)
+ throw new Error("start() on a thread that is alread busy!");
+ this.runnable = runnable;
+ notify();
+ }
}
public void run() {
try {
while(true) {
synchronized(this) {
- if (runnable==null)
+ if (runnable==null) {
synchronized(ThreadPool.this) {
/* if the idle array is full, just let ourselves die */
if (numIdleThreads > minIdleThreads && numThreads > minThreads) return;
idleThreads[numIdleThreads++] = this;
ThreadPool.this.notifyAll();
}
+ }
}
try {
synchronized(this) { while (runnable==null) wait(); }
runnable.run();
+ synchronized(this) { runnable = null; }
} catch (Exception e) { Log.error(this, e); }
- runnable = null;
}
} finally {
synchronized(ThreadPool.this) {