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 date format instances. This class is 013 intended for servlets/molly pages. Instead of static get/set methods, 014 this class must be instantiated and the instance methods used to get/set 015 the calendar object. This allows multiple instances of this class in the 016 webapp, with each instance being able to get/set a separate calendar. [If 017 the methods in this class were static, then only 1 calendar could be 018 get/set per thread]. 019 <p> 020 <font color=red><b>Each thread must remember to individually create a 021 separate calendar instance and store it via the set method</b></font>. The 022 usage idiom is: 023 <blockquote> 024 <pre> 025 <font color=blue> 026 //WebApp has a map of ThreadLocalDateFormat's and also a instance variable 027 //pointing to a default ThreadLocalDateFormat 028 ThreadLocalDateFormat mydf = WebApp.getThreadLocalDateFormat("foo"); 029 </font><font color=red> 030 if (mydf.isNull()) { 031 mydf.set(DateFormat.getInstance()); 032 } 033 </font><font color=blue> 034 DateFormat df = mydf.get(); 035 </font> 036 </pre> 037 </blockquote> 038 Note, the lines in red are always needed anywhere/anytime this class is used. 039 (note, it just so happens that the {@link DateFormat#getInstance} returns (at 040 least for now) a new object every time it is called, which is why it is 041 being used in the example above, else we would have to manually create a new 042 DateFormat instance instead). 043 */ 044 public final class ThreadLocalDateFormat 045 { 046 public ThreadLocalDateFormat() 047 { } 048 /* 049 Each get/set into the threadlocal must be seperately by each thread (the 050 initialValue() method is good for auto-assigning a new value but we 051 may need to assign a custom calendar value per thread, so we can't use 052 initialValue() 053 */ 054 private final ThreadLocal tldf = new ThreadLocal(); 055 056 public DateFormat get() 057 { 058 return (DateFormat) tldf.get(); 059 } 060 061 public void set(DateFormat df) 062 { 063 tldf.set(df); 064 } 065 066 public boolean isNull() 067 { 068 return tldf.get() == null; 069 } 070 071 public static void main (String args[]) throws Exception 072 { 073 final ThreadLocalDateFormat df1 = new ThreadLocalDateFormat(); 074 075 Thread t1 = new TestThread(false, df1); 076 Thread t2 = new TestThread(false, df1); 077 t1.start(); 078 t2.start(); 079 080 for (int n = 0; n < 100; n++) { 081 new TestThread(true, df1).start(); 082 } 083 } 084 085 static class TestThread extends Thread 086 { 087 boolean timing_only = false; 088 ThreadLocalDateFormat df; 089 TestThread(boolean timing_only, ThreadLocalDateFormat df) { 090 this.timing_only = timing_only; 091 this.df = df; 092 } 093 094 public void run() 095 { 096 //warm-up 097 if (df.isNull()) { 098 df.set(DateFormat.getInstance()); 099 } 100 101 Watch w = new NanoWatch(); 102 w.start(); 103 if (df.isNull()) { 104 df.set(DateFormat.getInstance()); 105 } 106 DateFormat c = df.get(); 107 w.stop(); 108 109 NumberFormat nf = NumberFormat.getNumberInstance(); 110 nf.setMinimumFractionDigits(2); 111 nf.setMaximumFractionDigits(2); 112 nf.setMinimumIntegerDigits(2); 113 114 if (timing_only) 115 System.out.println("[" + nf.format(w.getTime() / 1000000.00D) 116 + " ms]"); 117 else 118 System.out.println("[" + nf.format(w.getTime() / 1000000.00D) 119 + " ms]" + Thread.currentThread() 120 + "/DateFormat-ID:[" + System.identityHashCode(c) 121 + "] "+ c); 122 } 123 } 124 }