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
006package fc.util;
007
008import java.util.*;
009import java.text.*;
010
011/** 
012Useful to store thread-local instances of any object.  This class is intended
013for servlets/molly pages. Instead of static get/set methods, this class
014must be instantiated and the instance methods used to get/set the objom
015object. This allows multiple instances of this class in the webapp, with
016each 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
019object  instance and store it via the set method</b></font>. The usage idiom
020is:
021<blockquote>
022<pre>
023<font color=blue>
024//WebApp has a map of ThreadLocalObjects
025ThreadLocalObject tl_obj = WebApp.getThreadLocalObject("foo");
026</font><font color=red>
027if (tl_obj.isNull())  {
028  tl_obj.set(new obj());
029  }
030</font><font color=blue>
031Object obj = tl_obj.get();
032</font>
033</pre>
034</blockquote>
035Note, the lines in red are always needed anywhere/anytime this class is used.
036*/
037public final class ThreadLocalObject
038{
039public ThreadLocalObject()
040  { }
041/*
042Each get/set into the threadlocal must be seperately by each thread (the
043initialValue() method is good for auto-assigning a new value but we
044may need to assign a custom calendar value per thread, so we can't use
045initialValue()
046*/
047private final ThreadLocal tl = new ThreadLocal();
048
049public Object get()
050  {
051  return (Object) tl.get();
052  }
053
054public void set(Object cal)
055  {
056  tl.set(cal);
057  }
058
059public boolean isNull()
060  {
061  return tl.get() == null;
062  }
063
064public 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
078static 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}