001 // Copyright (c) 2001 Hursh Jain (http://www.mollypages.org)
002 // The Molly framework is freely distributable under the terms of an
003 // MIT-style license. For details, see the molly pages web site at:
004 // http://www.mollypages.org/. Use, modify, have fun !
005
006 package fc.util;
007
008 import java.util.*;
009 import java.text.*;
010
011 /**
012 Useful to store thread-local instances of any object. This class is intended
013 for servlets/molly pages. Instead of static get/set methods, this class
014 must be instantiated and the instance methods used to get/set the objom
015 object. This allows multiple instances of this class in the webapp, with
016 each instance being able to get/set a separate object.
017 <p>
018 <font color=red><b>Each thread must remember to individually create a separate
019 object instance and store it via the set method</b></font>. The usage idiom
020 is:
021 <blockquote>
022 <pre>
023 <font color=blue>
024 //WebApp has a map of ThreadLocalObjects
025 ThreadLocalObject tl_obj = WebApp.getThreadLocalObject("foo");
026 </font><font color=red>
027 if (tl_obj.isNull()) {
028 tl_obj.set(new obj());
029 }
030 </font><font color=blue>
031 Object obj = tl_obj.get();
032 </font>
033 </pre>
034 </blockquote>
035 Note, the lines in red are always needed anywhere/anytime this class is used.
036 */
037 public final class ThreadLocalObject
038 {
039 public ThreadLocalObject()
040 { }
041 /*
042 Each get/set into the threadlocal must be seperately by each thread (the
043 initialValue() method is good for auto-assigning a new value but we
044 may need to assign a custom calendar value per thread, so we can't use
045 initialValue()
046 */
047 private final ThreadLocal tl = new ThreadLocal();
048
049 public Object get()
050 {
051 return (Object) tl.get();
052 }
053
054 public void set(Object cal)
055 {
056 tl.set(cal);
057 }
058
059 public boolean isNull()
060 {
061 return tl.get() == null;
062 }
063
064 public static void main (String args[]) throws Exception
065 {
066 final ThreadLocalObject cal1 = new ThreadLocalObject();
067
068 Thread t1 = new TestThread(false, cal1);
069 Thread t2 = new TestThread(false, cal1);
070 t1.start();
071 t2.start();
072
073 for (int n = 0; n < 100; n++) {
074 new TestThread(true, cal1).start();
075 }
076 }
077
078 static class TestThread extends Thread
079 {
080 boolean timing_only = false;
081 ThreadLocalObject obj;
082 TestThread(boolean timing_only, ThreadLocalObject obj) {
083 this.timing_only = timing_only;
084 this.obj = obj;
085 }
086
087 public void run()
088 {
089 //warm up
090 if (obj.isNull()) {
091 obj.set(new Object());
092 }
093
094 Watch w = new NanoWatch();
095 w.start();
096 if (obj.isNull()) {
097 obj.set(new Object());
098 }
099 Object c = obj.get();
100 w.stop();
101
102 NumberFormat nf = NumberFormat.getNumberInstance();
103 nf.setMinimumFractionDigits(2);
104 nf.setMaximumFractionDigits(2);
105 nf.setMinimumIntegerDigits(2);
106
107 System.out.println("[" + nf.format(w.getTime() / 1000000.00D) + " ms]" + Thread.currentThread() + "/Object-ID:[" + System.identityHashCode(c) + "] "+ c);
108 }
109 }
110 }