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 Random instances. 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 random 015 object. This allows multiple instances of this class in the webapp, with 016 each instance being able to get/set a separate random generator. [If the methods in 017 this class were static, then only 1 random could be get/set per thread]. 018 <p> 019 <font color=red><b>Each thread must remember to individually create a separate 020 random instance and store it via the set method</b></font>. The usage idiom 021 is: 022 <blockquote> 023 <pre> 024 <font color=blue> 025 //WebApp has a map of ThreadLocalRandoms and also a instance variable 026 //pointing to a default ThreadLocalRandom 027 ThreadLocalRandom myrand = WebApp.getThreadLocalRandom("foo"); 028 </font><font color=red> 029 if (myrand.isNull()) { 030 myrand.set(new java.util.Random()); 031 } 032 </font><font color=blue> 033 Random rand = myrand.get(); 034 </font> 035 </pre> 036 </blockquote> 037 Note, the lines in red are always needed anywhere/anytime this class is used. 038 <p> 039 The methods in java.util.Random are synchronized (or at least they 040 internally use the synchronized <code>next(int)</code> method), so 041 these ThreadLocalRandoms are really only useful in heavily Multi threaded 042 apps where thread contention over a single random number generator 043 can slow things down. 044 */ 045 public final class ThreadLocalRandom 046 { 047 public ThreadLocalRandom() 048 { } 049 /* 050 Each get/set into the threadlocal must be seperately by each thread (the 051 initialValue() method is good for auto-assigning a new value but we 052 may need to assign a custom calendar value per thread, so we can't use 053 initialValue() 054 */ 055 private final ThreadLocal tlrand = new ThreadLocal(); 056 057 public Random get() 058 { 059 return (Random) tlrand.get(); 060 } 061 062 public void set(Random cal) 063 { 064 tlrand.set(cal); 065 } 066 067 public boolean isNull() 068 { 069 return tlrand.get() == null; 070 } 071 072 public static void main (String args[]) throws Exception 073 { 074 final ThreadLocalRandom cal1 = new ThreadLocalRandom(); 075 076 Thread t1 = new TestThread(false, cal1); 077 Thread t2 = new TestThread(false, cal1); 078 t1.start(); 079 t2.start(); 080 081 for (int n = 0; n < 100; n++) { 082 new TestThread(true, cal1).start(); 083 } 084 } 085 086 static class TestThread extends Thread 087 { 088 boolean timing_only = false; 089 ThreadLocalRandom rand; 090 TestThread(boolean timing_only, ThreadLocalRandom rand) { 091 this.timing_only = timing_only; 092 this.rand = rand; 093 } 094 095 public void run() 096 { 097 //warm up 098 if (rand.isNull()) { 099 rand.set(new java.util.Random()); 100 } 101 102 Watch w = new NanoWatch(); 103 w.start(); 104 if (rand.isNull()) { 105 rand.set(new java.util.Random()); 106 } 107 Random c = rand.get(); 108 w.stop(); 109 110 NumberFormat nf = NumberFormat.getNumberInstance(); 111 nf.setMinimumFractionDigits(2); 112 nf.setMaximumFractionDigits(2); 113 nf.setMinimumIntegerDigits(2); 114 115 if (timing_only) 116 System.out.println("[" + nf.format(w.getTime() / 1000000.00D) + " ms]"); 117 else 118 System.out.println("[" + nf.format(w.getTime() / 1000000.00D) + " ms]" + Thread.currentThread() + "/Calendar-ID:[" + System.identityHashCode(c) + "] "+ c); 119 } 120 } 121 }