User: jung
Date: 00/12/22 00:35:59
Added: src/de/infor/ce/util How Pooling Should Work .dfSequence
PooledThread.java PooledThreadLocal.java
Log:
pooled threads made an explicit class.
pooled threadlocals will garbage attached resources upon reentering the pool!
Revision Changes Path
No revision
No revision
No revision
No revision
No revision
1.1 zoap/src/de/infor/ce/util/PooledThread.java
Index: PooledThread.java
===================================================================
/*
* $Id: PooledThread.java,v 1.1 2000/12/22 08:35:58 jung Exp $
* Copyright 2000 (C) infor:business solutions AG, Hauerstrasse 12,
* D-66299 Friedrichsthal, Germany. All Rights Reserved.
*
* License Statement
*
* Redistribution and use of this software and associated documentation
("Software"), with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain copyright statements and
notices.
* Redistributions must also contain a copy of this document.
*
* 2. Redistributions in binary form must reproduce the attached copyright
notice, this list of
* conditions and the following disclaimer in the documentation and/or
other materials provided
* with the distribution.
*
* 3. The end-user documentation included with the redistribution, if any,
must include the following
* acknowledgment: "This product includes software developed by infor:
business solutions AG
* (http://www.infor.de/)." Alternately, this acknowledgment may appear
in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The name "infor" must not be used to endorse or promote products
derived from this
* Software without prior written permission of infor: business solutions
AG.
* For written permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this Software may not be called "infor" nor may
"infor" appear
* in their names without prior written permission of infor: business
solutions AG. infor
* is a registered trademark of infor:business solutions AG.
*
* Disclaimer
*
* THIS SOFTWARE IS PROVIDED BY INFOR: BUSINESS SOLUTIONS AG AND CONTRIBUTORS "AS
IS" AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
*
* IN NO EVENT SHALL INFOR: BUSINESS SOLUTIONS AG OR ITS CONTRIBUTORS BE LIABLE
FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package de.infor.ce.util;
import java.util.Map;
import java.util.Collections;
/** a thread that is part of a pool */
/** inner class that implements poolable threads */
class PooledThread extends Thread {
/** the pool to which this thread belongs */
final private ThreadPool threadPool;
/**
* should this thread keep on running?
* should be only settable to false
*/
private boolean running = true;
/** what would be the next task to perform? */
private Runnable runnable;
/** list of pooled locals, package-wide access (@see PooledThreadLocal) */
Map pooledThreadLocals;
/** construct new pooled thread for a particular pool */
PooledThread(ThreadPool pool) {
super();
threadPool = pool;
init(null);
}
/** construct new thread with a given runnable */
PooledThread(ThreadPool pool, Runnable target) {
super();
threadPool = pool;
init(target);
}
/** new pooled thread assigned to a particular group */
PooledThread(ThreadPool pool, ThreadGroup group, Runnable target) {
super(group,(Runnable) null);
threadPool = pool;
init(target);
}
/** new thread with a given name */
PooledThread(ThreadPool pool, String name) {
super(name);
threadPool = pool;
init(null);
}
/** new thread with given group and name */
PooledThread(ThreadPool pool, ThreadGroup group, String name) {
super(group, name);
threadPool = pool;
init(null);
}
/** new thread with target and name */
PooledThread(ThreadPool pool, Runnable target, String name) {
super(name);
threadPool = pool;
init(target);
}
/** new thread with given group, runnable and name */
PooledThread(ThreadPool pool,ThreadGroup group, Runnable target, String name) {
super(group, name);
threadPool = pool;
init(target);
}
/** initialise locals and such */
private void init(Runnable initialRunnable) {
pooledThreadLocals = Collections.EMPTY_MAP;
running = true;
this.runnable = initialRunnable;
}
/**
* do something
* meaningful over a longer period of time
*/
public void run() {
if (Environment.DEBUG_UTIL && Environment.DEBUG_THREADPOOL)
Environment.out.println(this.toString() + ".run()");
while (running) {
if (runnable != null) {
try {
runnable.run();
} catch (Exception e) {
// catch any internal exception to continue working
}
// Clear work, this is safe as the thread should be non-pooled in
this state
runnable = null;
}
// clean up the threads local values
clean();
// Return to pool
threadPool.returnThread(this);
if (Environment.DEBUG_UTIL && Environment.DEBUG_THREADPOOL)
Environment.out.println(this.toString() + ".run():" + " going to
sleep.");
// Wait for work to become available
synchronized(this) {
if (running && runnable == null) {
try {
this.wait();
} catch (InterruptedException e) {
}
}
}
if (Environment.DEBUG_UTIL && Environment.DEBUG_THREADPOOL)
Environment.out.println(this.toString() + ".run(): awake.");
} // while
if (Environment.DEBUG_UTIL && Environment.DEBUG_THREADPOOL)
Environment.out.println(this.toString() + ".run(): dead.");
} // run
/**
* this method allows to start an arbitrary runnable in this thread,
* is guarantueed to run only once
*/
void run(Runnable runnable) {
if (Environment.DEBUG_UTIL && Environment.DEBUG_THREADPOOL)
Environment.out.println(this.toString() + ".run(" + runnable + ")");
synchronized(this) {
if (running && this.runnable == null) {
if (Environment.DEBUG_UTIL && Environment.DEBUG_THREADPOOL)
Environment.out.print(this.toString() + ".run(" + runnable + "):
has lock.\n");
this.runnable = runnable;
this.notify();
} else {
// this should never, never happen
throw new RuntimeException("Could not run runnable on because pooled
thread is dead or occupied.");
}
}
}
/** and finally, the signal to die ASAP */
protected void finalize() {
if (Environment.DEBUG_UTIL && Environment.DEBUG_THREADPOOL)
Environment.out.println(this.toString() + ".finalize()");
synchronized(this) {
if (running && runnable == null) {
if (Environment.DEBUG_UTIL && Environment.DEBUG_THREADPOOL)
Environment.out.print(this.toString() + ".finalize(): has
lock.\n");
running = false;
this.notify();
} else {
throw new RuntimeException("could not finalize finalized or tasked
thread");
} // if
} // sync
} // die
/** cleanup the locals */
private void clean() {
if(Environment.DEBUG_UTIL && Environment.DEBUG_THREADPOOL)
Environment.out.println(toString()+".clean()");
pooledThreadLocals = Collections.EMPTY_MAP;
}
}
1.1 zoap/src/de/infor/ce/util/PooledThreadLocal.java
Index: PooledThreadLocal.java
===================================================================
package de.infor.ce.util;
/**
* $Id: PooledThreadLocal.java,v 1.1 2000/12/22 08:35:58 jung Exp $
* Copyright 2000 by infor: business solutions AG
* Hauerstra�e 12, D-66299 Friedrichsthal, Germany
* All rights reserved.
*
* This software is the confidential and proprietary information
* of infor: business solutions AG ("Confidential Information"). You
* shall not disclose such Confidential Information and shall use
* it only in accordance with the terms of the license agreement
* you entered into with infor AG.
*/
import java.util.Map;
import java.util.Collections;
import java.util.HashMap;
/**
* a thread local that will be dumped if the
* corresponding thread will be pooled.
*
* @see <related>
* @author $Author: jung $
* @version $Revision: 1.1 $
*/
public class PooledThreadLocal extends ThreadLocal {
/**
* Initial capacity of per-thread HashMap from ThreadLocal to value.
* The size should be approximately twice the the number of thread local
* variables that thread might have.
*/
private static final int LOCAL_INITIAL_CAPACITY = 11;
/** Creates a ThreadLocal variable. */
public PooledThreadLocal() {
super();
secondKey = new SecureKey();
}
/**
* Secure key representing this thread local variable. This key is used
* in preference to the ThreadLocal object itself, to map this variable to
* its per-thread value, to prevent an attacker from overriding the equals
* method to spoof another ThreadLocal and steal its value.
*/
Object secondKey;
/**
* Returns the value in the calling thread's copy of this ThreadLocal
* variable. Creates and initializes the copy if this is the first time
* the thread has called this method.
*
* @return the value of this ThreadLocal
*/
public Object get() {
Thread ourThread = Thread.currentThread();
if (ourThread instanceof PooledThread) {
Map map = ((PooledThread)ourThread).pooledThreadLocals;
Object value = map.get(secondKey);
if (value == null && !map.containsKey(secondKey)) {
if (map == Collections.EMPTY_MAP)
map = ((PooledThread)ourThread).pooledThreadLocals =
new HashMap(LOCAL_INITIAL_CAPACITY);
value = initialValue();
map.put(secondKey, value);
}
return value;
} else {
return super.get();
}
}
/**
* Sets the calling thread's instance of this ThreadLocal variable
* to the given value. This is only used to change the value from
* the one assigned by the initialValue method, and many applications
* will have no need for this functionality.
*
* @param value the value to be stored in the calling threads' copy of
* this ThreadLocal.
*/
public void set(Object value) {
Thread ourThread = Thread.currentThread();
if (ourThread instanceof PooledThread) {
Map map = ((PooledThread)ourThread).pooledThreadLocals;
if (map == Collections.EMPTY_MAP)
map = ((PooledThread)ourThread).pooledThreadLocals =
new HashMap(LOCAL_INITIAL_CAPACITY);
map.put(secondKey, value);
} else {
super.set(value);
}
}
/**
* An object of this class is used in place of the ThreadLocal itself
* as a key in the per-Thread ThreadLocal->value Map. This prevents
* a "spoof attack" where one ThreadLocal pretends to be another
* by overriding the equals (and hashCode) method and returning true
* when it should return false.
*/
class SecureKey {
}
}