| /* java.lang.InheritableThreadLocal | |
| Copyright (C) 2000, 2001 Free Software Foundation, Inc. | |
| This file is part of GNU Classpath. | |
| GNU Classpath is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 2, or (at your option) | |
| any later version. | |
| GNU Classpath 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 | |
| General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with GNU Classpath; see the file COPYING. If not, write to the | |
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
| 02111-1307 USA. | |
| As a special exception, if you link this library with other files to | |
| produce an executable, this library does not by itself cause the | |
| resulting executable to be covered by the GNU General Public License. | |
| This exception does not however invalidate any other reasons why the | |
| executable file might be covered by the GNU General Public License. */ | |
| package java.lang; | |
| import java.util.Iterator; | |
| import java.util.HashSet; | |
| import java.util.Map; | |
| import java.util.Set; | |
| import java.util.WeakHashMap; | |
| /** | |
| * ThreadLocal whose value is inherited by child Threads. | |
| * The value of the InheritableThreadLocal associated with the (parent) Thread | |
| * on the moment that it creates a new (child) Thread is set as the value that | |
| * is associated with the new (child) Thread. | |
| * <p> | |
| * It is possible to make the value associated with the child Thread a function | |
| * of the value that is associated with the parent Thread by overriding the | |
| * <code>childValue()</code> method. | |
| * | |
| * @since 1.2 | |
| * @author Mark Wielaard (mark@klomp.org) | |
| */ | |
| public class InheritableThreadLocal extends ThreadLocal { | |
| /** | |
| * Maps Threads to a Set of InheritableThreadLocals | |
| * (the heritage of that Thread). | |
| * Uses a WeakHashMap so if the Thread is garbage collected the reference | |
| * to that Set disappears. | |
| * Both <code>AddToHeritage</code> access and modify it so they have to | |
| * synchronize on the threadMap when they do. | |
| */ | |
| private static Map threadMap = new WeakHashMap(); | |
| /** | |
| * Creates a new InheritableThreadLocal that has no values associated | |
| * with it yet. | |
| */ | |
| public InheritableThreadLocal() { | |
| super(); | |
| } | |
| /** | |
| * Determines the value associated with a newly created child Thread | |
| * as a function of the value associated with the currently executing | |
| * (parent) Thread. | |
| * <p> | |
| * The default implementation just returns the parentValue. | |
| */ | |
| protected Object childValue(Object parentValue) { | |
| return parentValue; | |
| } | |
| /** | |
| * Adds this <code>InheritableThreadLocal</code> to the heritage of the | |
| * current Thread and returns the value of the <code>ThreadLocal</code> | |
| * for the Thread. The value will be either the last value that the | |
| * current Thread has set, or the childValue of the last value that the | |
| * parent Thread set before the current Thread was created, or the | |
| * initialValue of the <code>ThreadLocal</code>. | |
| * | |
| * @see ThreadLocal#get() | |
| */ | |
| public Object get() { | |
| addToHeritage(); | |
| return super.get(); | |
| } | |
| /** | |
| * Adds this <code>InheritableThreadLocal</code> to the heritage of the | |
| * current Thread and sets the value of the <code>ThreadLocal</code> | |
| * for the Thread. | |
| * | |
| * @see ThreadLocal#set(Object) | |
| */ | |
| public void set(Object value) { | |
| addToHeritage(); | |
| super.set(value); | |
| } | |
| /** | |
| * Adds this <code>InheritableThreadLocal</code> to the heritage | |
| * of the current Thread. | |
| */ | |
| private void addToHeritage() { | |
| Thread currentThread = Thread.currentThread(); | |
| Set heritage; | |
| synchronized(threadMap) { | |
| heritage = (Set)threadMap.get(currentThread); | |
| } | |
| // Note that we don't have to synchronize on the heritage Set | |
| // since only this Thread (or the parent Thread when creating | |
| // the heritage) ever modifies it. | |
| if (heritage == null) { | |
| heritage = new HashSet(); | |
| synchronized(threadMap) { | |
| threadMap.put(currentThread, heritage); | |
| } | |
| } | |
| if (!heritage.contains(this)) { | |
| heritage.add(this); | |
| } | |
| } | |
| /** | |
| * Generates the childValues of all <code>InheritableThreadLocal</code>s | |
| * that are in the heritage of the current Thread for the newly created | |
| * childThread. | |
| * Should be called from the contructor of java.lang.Thread. | |
| */ | |
| static void newChildThread(Thread childThread) { | |
| // The currentThread is the parent of the new thread | |
| Thread parentThread = Thread.currentThread(); | |
| // Inherit all the InheritableThreadLocals of the parent thread | |
| Set heritage; | |
| synchronized(threadMap) { | |
| heritage = (Set)threadMap.get(parentThread); | |
| } | |
| // Note that we don't have to synchronize on the heritage Set | |
| // since only this Thread (or the parent Thread when creating | |
| // the heritage) ever modifies it. | |
| if (heritage != null) { | |
| synchronized(threadMap) { | |
| threadMap.put(childThread, new HashSet(heritage)); | |
| } | |
| // And constructs all the new child values | |
| // (has to be done now that we are executing in the parentThread) | |
| Iterator it = heritage.iterator(); | |
| while (it.hasNext()) { | |
| InheritableThreadLocal local = | |
| (InheritableThreadLocal) it.next(); | |
| // Note that the parentValue cannot be null | |
| // If it was it would not be in the heritage | |
| Object parentValue = local.get(parentThread).getValue(); | |
| Object childValue = local.childValue(parentValue); | |
| ThreadLocal.Value v = new ThreadLocal.Value(childValue); | |
| local.set(childThread, v); | |
| } | |
| } | |
| } | |
| } |