001: /*
002: * @(#)WorkerThreadPool.java 1.3 06/08/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package com.sun.jumpimpl.ixc;
029:
030: /**
031: * A WorkerThreadPool executes a Runnable in the background. For efficiency, a
032: * simple thread pool is maintained. Threads are created when needed,
033: * and a thread with no work to do for ten seconds is destroyed.
034: * <p>
035: * It would make sense to use this WorkerThreadPool class in the app manager,
036: * e.g. for xlet lifecycle control, since sending those events is rare.
037: * <p>
038: * This class assumes that creation and destruction of java.lang.Thread
039: * instances is relatively expensive. Of course, java.lang.Thread might
040: * do its own pooling of underlying native threads; if this is so,
041: * then it may be somewhat more efficient to just create a new
042: * java.lang.Thread for each call.
043: */
044:
045: public class WorkerThreadPool implements Runnable {
046:
047: private static int TIMEOUT = 10000; // Timeout after 10 seconds
048: private static Object LOCK = new Object();
049: private static int num = 1; // For unique names, which helps debugging
050:
051: // Linked list of available workers, with the most recently used
052: // worker first.
053: private static WorkerThreadPool available = null;
054:
055: private Thread thread;
056: private Runnable work = null;
057: private WorkerThreadPool next = null;
058:
059: private static int counter = 0;
060: private static int LIMIT = 10; // Max number of threads.
061:
062: /**
063: * Run r in the background, returning immediatedly.
064: *
065: * @param priority Thread priority for this task
066: * @param r Task to run
067: **/
068: public static void execute(int priority, Runnable r) {
069: WorkerThreadPool w;
070: while (counter > LIMIT && available == null) {
071: try {
072: Thread.currentThread().wait(1000);
073: } catch (Exception e) {
074: }
075: }
076: synchronized (LOCK) {
077: if (available == null) {
078: w = new WorkerThreadPool();
079: counter++;
080: } else {
081: w = available;
082: available = available.next;
083: }
084: w.thread.setPriority(priority);
085: w.work = r;
086: // We can't synchronize on w here, because the locking
087: // order is first WorkerThreadPool lock, then global lock.
088: }
089: synchronized (w) {
090: w.notifyAll();
091: }
092: }
093:
094: private WorkerThreadPool() {
095: int n = num++;
096: thread = new Thread(this , "WorkerThreadPool-" + n);
097: thread.setPriority(9);
098: thread.setDaemon(true);
099: thread.start();
100: }
101:
102: /**
103: * This is an internal method of WorkerThreadPool, and should not
104: * be called by clients.
105: **/
106: public void run() {
107: Runnable r = null;
108: long lastUsed = System.currentTimeMillis();
109: for (;;) {
110: synchronized (this ) {
111: while (work == null) {
112: long tm = lastUsed + TIMEOUT
113: - System.currentTimeMillis();
114: if (tm <= 0L) { // timed out
115: synchronized (LOCK) {
116: if (work == null) {
117: //System.out.println("@@ " + thread + " unused, terminating.");
118: if (available == this ) {
119: available = this .next;
120: } else if (available == null) {
121: // Shouldn't happen
122: } else {
123: WorkerThreadPool w = available;
124: while (w != null) {
125: if (w.next == this ) {
126: w.next = this .next;
127: break;
128: } else {
129: w = w.next;
130: }
131: }
132: }
133: counter--;
134: return;
135: }
136: }
137: } else {
138: try {
139: wait(tm);
140: } catch (InterruptedException ex) {
141: // ignore.
142: }
143: }
144: }
145: r = work;
146: }
147: try {
148: r.run();
149: } catch (Throwable t) {
150: t.printStackTrace();
151: } finally {
152: synchronized (this ) {
153: work = null;
154: lastUsed = System.currentTimeMillis();
155: thread.setPriority(9);
156: synchronized (LOCK) {
157: this.next = available;
158: available = this;
159: }
160: }
161: }
162: }
163: }
164: }
|