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    }