1. /*
  2. * @(#)InheritableThreadLocal.java 1.10 00/02/02
  3. *
  4. * Copyright 1998-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package java.lang;
  11. import java.util.*;
  12. /**
  13. * This class extends ThreadLocal to provide inheritance of values from parent
  14. * Thread to child Thread: when a child thread is created, the child receives
  15. * initial values for all InheritableThreadLocals for which the parent has
  16. * values. Normally the child's values will be identical to the parent's;
  17. * however, the child's value can be made an arbitrary function of the parent's
  18. * by overriding the childValue method in this class.
  19. *
  20. * <p>InheritableThreadLocal variables are used in preference to ordinary
  21. * ThreadLocal variables when the per-thread-attribute being maintained in the
  22. * variable (e.g., User ID, Transaction ID) must be automatically transmitted
  23. * to any child threads that are created.
  24. *
  25. * @author Josh Bloch
  26. * @version 1.10, 02/02/00
  27. * @see ThreadLocal
  28. * @since 1.2
  29. */
  30. public class InheritableThreadLocal extends ThreadLocal {
  31. /**
  32. * Initial capacity of per-thread HashMap from ThreadLocal to value.
  33. * The size should be approximately twice the the number of inheritable
  34. * thread local variables that thread might have.
  35. */
  36. private static final int INITIAL_CAPACITY = 11;
  37. /**
  38. * Creates an InheritableThreadLocal variable.
  39. */
  40. public InheritableThreadLocal() {
  41. }
  42. /**
  43. * Returns the value in the calling thread's copy of this ThreadLocal
  44. * variable. Creates and initializes the copy if this is the first time
  45. * the thread has called this method.
  46. */
  47. public Object get() {
  48. Thread ourThread = Thread.currentThread();
  49. Map map = ourThread.inheritableThreadLocals;
  50. Object value = map.get(key);
  51. if (value==null && !map.containsKey(key)) {
  52. if (map == Collections.EMPTY_MAP)
  53. map = ourThread.inheritableThreadLocals
  54. = new HashMap(INITIAL_CAPACITY);
  55. value = initialValue();
  56. map.put(key, value);
  57. }
  58. return value;
  59. }
  60. /**
  61. * Sets the calling thread's instance of this ThreadLocal variable
  62. * to the given value. This is only used to change the value from
  63. * the one assigned by the initialValue method, and many applications
  64. * will have no need for this functionality.
  65. *
  66. * @param value the value to be stored in the calling threads' copy of
  67. * this ThreadLocal.
  68. */
  69. public void set(Object value) {
  70. Thread ourThread = Thread.currentThread();
  71. Map map = ourThread.inheritableThreadLocals;
  72. if (map == Collections.EMPTY_MAP)
  73. map = ourThread.inheritableThreadLocals
  74. = new HashMap(INITIAL_CAPACITY);
  75. map.put(key, value);
  76. }
  77. /**
  78. * Computes the child's initial value for this InheritableThreadLocal
  79. * as a function of the parent's value at the time the child Thread is
  80. * created. This method is called from within the parent thread before
  81. * the child is started.
  82. * <p>
  83. * This method merely returns its input argument, and should be overridden
  84. * if a different behavior is desired.
  85. *
  86. * @param parentValue the parent thread's value
  87. * @return the child thread's initial value
  88. */
  89. protected Object childValue(Object parentValue) {
  90. return parentValue;
  91. }
  92. /**
  93. * Passes the ThreadLocal values represented by the specified list of
  94. * Entries onto the specified child Thread. (The child's value is
  95. * computed from the parent's as per the childValue method.) This
  96. * method is invoked (only) at Thread creation time, by Thread.init.
  97. */
  98. static void bequeath(Thread parent, Thread child) {
  99. Map parentMap = parent.inheritableThreadLocals;
  100. if (parentMap == Collections.EMPTY_MAP)
  101. return;
  102. Map childMap = child.inheritableThreadLocals
  103. = new HashMap(INITIAL_CAPACITY);
  104. for (Iterator i=parentMap.entrySet().iterator(); i.hasNext(); ) {
  105. Map.Entry e = (Map.Entry) i.next();
  106. SecureKey k = (SecureKey) e.getKey();
  107. InheritableThreadLocal itl = (InheritableThreadLocal)k.threadLocal();
  108. childMap.put(k, itl.childValue(e.getValue()));
  109. }
  110. }
  111. }