JDK 1.2 ThreadLocal class

Archie Cobbs archie at whistle.com
Tue Aug 18 12:38:03 PDT 1998


I've implemented java.lang.ThreadLocal and java.lang.InheritableThreadLocal
classes from the JDK 1.2 spec.

Included below is the relevant patch (including two new files) and also
a test program.

-Archie

___________________________________________________________________________
Archie Cobbs   *   Whistle Communications, Inc.  *   http://www.whistle.com
-------------- next part --------------
diff -ur --unidirectional-new-file lang.old/InheritableThreadLocal.java lang.new/InheritableThreadLocal.java
--- lang.old/InheritableThreadLocal.java	Wed Dec 31 16:00:00 1969
+++ lang.new/InheritableThreadLocal.java	Tue Aug 18 12:34:50 1998
@@ -0,0 +1,18 @@
+/*
+ * Java core library component.
+ *
+ * Copyright (c) 1997, 1998
+ *      Transvirtual Technologies, Inc.  All rights reserved.
+ *
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file.
+ */
+
+package java.lang;
+
+public class InheritableThreadLocal extends ThreadLocal {
+	protected Object childValue(Object parentValue) {
+		return parentValue;
+	}
+}
+
diff -ur --unidirectional-new-file lang.old/Thread.java lang.new/Thread.java
--- lang.old/Thread.java	Tue Aug 18 11:17:42 1998
+++ lang.new/Thread.java	Tue Aug 18 12:34:50 1998
@@ -10,6 +10,8 @@
 
 package java.lang;
 
+import java.util.Hashtable;
+import java.util.Enumeration;
 import kaffe.util.Deprecated;
 
 public class Thread implements Runnable {
@@ -32,6 +34,7 @@
   private kaffe.util.Ptr exceptObj;
   private kaffe.util.Ptr jnireferences;
   private boolean dying;
+  private Hashtable threadLocals;
 
   public native int countStackFrames();
   public static native Thread currentThread();
@@ -73,8 +76,10 @@
 
   public Thread(ThreadGroup group, Runnable target, String name)
   {
+    final Thread parent = Thread.currentThread();
+
     if (group == null) {
-      this.group = Thread.currentThread().getThreadGroup();
+      this.group = parent.getThreadGroup();
     }
     else {
       this.group = group;
@@ -86,7 +91,20 @@
     this.target = target;
     this.interrupting = false;
 
-    int tprio = Thread.currentThread().getPriority();
+    /*
+     * Inherit all inheritable thread-local variables from parent to child
+     */
+    if (parent.threadLocals != null) {
+      for (Enumeration e = parent.threadLocals.keys(); e.hasMoreElements(); ) {
+	Object key = e.nextElement();
+	if (key instanceof InheritableThreadLocal) {
+	  InheritableThreadLocal i = (InheritableThreadLocal) key;
+	  i.set(this, i.childValue(i.get()));
+	}
+      }
+    }
+
+    int tprio = parent.getPriority();
     int gprio = this.group.getMaxPriority();
     if (tprio < gprio) {
       setPriority0(tprio);
@@ -95,7 +113,7 @@
       setPriority0(gprio);
     }
 
-    setDaemon(Thread.currentThread().isDaemon());
+    setDaemon(parent.isDaemon());
   }
 
   private static String generateName()
@@ -287,6 +305,17 @@
   protected void finalize()
   {
     finalize0();
+  }
+
+  /*
+   * This method is used by java.lang.ThreadLocal. We don't
+   * allocate the hashtable with each thread until we have to.
+   */
+  Hashtable getThreadLocals() {
+    if (threadLocals == null) {
+      threadLocals = new Hashtable();
+    }
+    return threadLocals;
   }
 
   private final native void finalize0();
diff -ur --unidirectional-new-file lang.old/ThreadLocal.java lang.new/ThreadLocal.java
--- lang.old/ThreadLocal.java	Wed Dec 31 16:00:00 1969
+++ lang.new/ThreadLocal.java	Tue Aug 18 12:34:50 1998
@@ -0,0 +1,49 @@
+/*
+ * Java core library component.
+ *
+ * Copyright (c) 1997, 1998
+ *      Transvirtual Technologies, Inc.  All rights reserved.
+ *
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file.
+ */
+
+package java.lang;
+
+import java.util.Hashtable;
+
+public class ThreadLocal {
+
+	/*
+	 * Since you can't store null as the value in a hashtable,
+	 * we use this object to represent a value of null.
+	 */
+	private static final Object NULL_VALUE = new Object();
+
+	protected Object initialValue() {
+		return null;
+	}
+
+	public Object get() {
+		return get(Thread.currentThread());
+	}
+
+	public void set(Object value) {
+		set(Thread.currentThread(), value);
+	}
+
+	Object get(Thread thread) {
+		Hashtable h = thread.getThreadLocals();
+		if (!h.containsKey(this)) {
+			set(thread, initialValue());
+		}
+		Object value = h.get(this);
+		return value == NULL_VALUE ? null : value;
+	}
+
+	void set(Thread thread, Object value) {
+		thread.getThreadLocals().put(this,
+			value == null ? NULL_VALUE : value);
+	}
+}
+
-------------- next part --------------

public class ThreadLocalTest {

  private static int threadNum;

  private static ThreadLocal tl = new ThreadLocal() {
    protected Object initialValue() {
      return " TL initial";
    }
  };

  private static InheritableThreadLocal itl = new InheritableThreadLocal() {
    protected Object initialValue() {
      return "ITL initial";
    }
    protected Object childValue(Object pval) {
      return (String) pval + " inherited from " + Thread.currentThread().getName();
    }
  };

  private static class TestThread extends Thread {
    private int num;
    private int delay;
    private boolean spawn;
    public TestThread(int delay, boolean spawn) {
      super("" + ++threadNum);
      this.num = threadNum;
      this.delay = delay;
      this.spawn = spawn;
    }
    public void run() {
      for (int k = 0; k < 4; k++) {

	try {
	  sleep(delay);
	} catch (InterruptedException e) {}

	System.out.println("Thread " + getName() + " interation " + k + ":");
	System.out.println("\t TL: " + ThreadLocalTest.tl.get());
	System.out.println("\tITL: " + ThreadLocalTest.itl.get());

	tl.set(tl.get() + " changed by " + num + " at k == " + k);
	itl.set(((k & 1) == 0) ? null : ("set by " + num + " at k == " + k));

	if (spawn && k == num) {
	  TestThread t1 = new TestThread(delay, false);
	  System.out.println("\tCreating new thread " + t1.getName());
	  t1.start();
	  TestThread t2 = new TestThread(delay, false);
	  System.out.println("\tCreating new thread " + t2.getName());
	  t2.start();
	}
      }
    }
  }

  public static void main(String[] args) {
    new TestThread(500, true).start();
    new TestThread(550, true).start();
  }
}



More information about the kaffe mailing list