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