KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javolution > context > PoolContext


1 /*
2  * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
3  * Copyright (C) 2006 - Javolution (http://javolution.org/)
4  * All rights reserved.
5  *
6  * Permission to use, copy, modify, and distribute this software is
7  * freely granted, provided that this notice is preserved.
8  */

9 package javolution.context;
10
11 import j2me.lang.UnsupportedOperationException;
12 import j2me.lang.ThreadLocal;
13 import j2mex.realtime.MemoryArea;
14 import javolution.Javolution;
15 import javolution.JavolutionError;
16 import javolution.text.Text;
17 import javolution.util.FastTable;
18 import javolution.xml.XMLFormat;
19 import javolution.xml.stream.XMLStreamException;
20
21 /**
22  * <p> This class represents a pool context; it is used to recycle objects
23  * transparently, reduce memory allocation and avoid garbage collection.
24  * Pool contexts do not require any form of synchronization (internally or
25  * externally) and result in faster execution time when many temporary
26  * objects are produced (they are recycled all at once).</p>
27  *
28  * <p> Threads executing in a pool context may allocate objects from
29  * the context's pools (also called "stack") through an
30  * {@link ObjectFactory}. Allocated objects are recycled automatically
31  * upon {@link PoolContext#exit exit}. This recycling is almost
32  * instantaneous (unlike garbage collection). For example:[code]
33  * public class DenseVector<F extends Field<F>> extends Vector<F> {
34  * ...
35  * public F times(Vector<F> that) {
36  * if (this.getDimension() != that.getDimension())
37  * throw new DimensionException();
38  * PoolContext.enter(); // Marks thread-local stack/pool.
39  * try {
40  * F sum = this.get(0).times(that.get(0));
41  * for (int i = 1, n = getDimension(); i < n; i++) {
42  * sum = sum.plus(this.get(i).times(that.get(i))); // Stack allocated objects
43  * }
44  * return sum.export(); // Moves sum outside of the current marked stack.
45  * } finally {
46  * PoolContext.exit(); // Resets the thread-local stack/pool (immediate).
47  * }
48  * }
49  * }[/code]</p>
50  *
51  * <p> Objects allocated within a pool context should not be directly
52  * referenced outside of the context unless they are
53  * {@link RealtimeObject#export exported} (e.g. result being returned)
54  * or {@link RealtimeObject#preserve preserved} (e.g. shared static
55  * instance). If this simple rule is followed, then pool context are
56  * completely safe. In fact, pool contexts promote the use of immutable
57  * objects (as their allocation cost is then negligible) and often lead
58  * to safer, faster and more robust applications.</p>
59  *
60  * <p> Finally for RTSJ VM, the framework guarantees that all pool objects
61  * belongs to the same memory area (the memory area where the pool context
62  * resides). Pool contexts allocated in ImmortalMemory (e.g. static) can
63  * safely be used by <code>NoHeapRealtimeThread</code> with Javolution
64  * doing the recycling (Note: ImmortalMemory is never garbage
65  * collected and ScopedMemory can only be used for temporary data).</p>
66  *
67  * @author <a HREF="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
68  * @version 4.2, December 14, 2006
69  */

70 public class PoolContext extends Context {
71
72     /**
73      * Holds the context factory.
74      */

75     private static Factory FACTORY = new Factory() {
76         protected Object JavaDoc create() {
77             return new PoolContext();
78         }
79     };
80
81     /**
82      * Indicates if pools are enabled.
83      */

84     private static final LocalContext.Reference ENABLED
85          = new LocalContext.Reference(new Boolean JavaDoc(true));
86
87     /**
88      * Holds the XML format.
89      */

90     final static XMLFormat XML = new XMLFormat(
91             Javolution.j2meGetClass("javolution.context.PoolContext")) {
92  
93         public void read(InputElement xml, Object JavaDoc obj) throws XMLStreamException {
94             PoolContext ctx = (PoolContext)obj;
95             Class JavaDoc cls = ctx._allPools.getClass();
96             ctx._allPools.addAll((FastTable)xml.get("Pools", cls));
97         }
98
99         public void write(Object JavaDoc obj, OutputElement xml) throws XMLStreamException {
100             PoolContext ctx = (PoolContext)obj;
101             Class JavaDoc cls = ctx._allPools.getClass();
102             xml.add(ctx._allPools, "Pools", cls);
103         }
104     };
105
106     /**
107      * Holds the collection of thread-local pools (to recycle upon exit).
108      * There is a limited number of concurrent executors; and therefore
109      * thread local pools.
110      */

111     private final FastTable _allPools = new FastTable();
112
113     /**
114      * Indicates if object pooling is enabled.
115      */

116     private boolean _isEnabled = true;
117
118     /**
119      * Holds the thread-local pools (for explicit object recycling).
120      */

121     private final ThreadLocal JavaDoc _localPools = new ThreadLocal JavaDoc() {
122         private Runnable JavaDoc _createLocalPools = new Runnable JavaDoc() {
123             public void run() {
124                 LocalPools pools = new LocalPools(true);
125                 pools._owner = Thread.currentThread();
126                 _allPools.add(pools);
127             }
128         };
129
130         protected synchronized Object JavaDoc initialValue() {
131             // First try to reuse existing pool (e.g. deserialized context).
132
for (int i=0; i < _allPools.size(); i++) {
133                 LocalPools pools = (LocalPools) _allPools.get(i);
134                 if (pools._owner == null) {
135                     pools._owner = Thread.currentThread();
136                     return pools;
137                 }
138             }
139             // Else create a new local pools in this context memory area.
140
MemoryArea.getMemoryArea(PoolContext.this).executeInArea(
141                     _createLocalPools);
142             return _allPools.getLast();
143         }
144     };
145
146     /**
147      * Default constructor.
148      */

149     public PoolContext() {
150     }
151
152     /**
153      * Returns the current pool context or <code>null<code> if the current
154      * thread executes within a {@link HeapContext}.
155      *
156      * @return the current pool context.
157      */

158     public static/*PoolContext*/Context current() {
159         for (Context ctx = Context.current(); ctx != null; ctx = ctx.getOuter()) {
160             if (ctx instanceof PoolContext)
161                 return (PoolContext) ctx;
162             if (ctx instanceof HeapContext)
163                 return null;
164         }
165         throw new JavolutionError("No heap context or pool context");
166     }
167
168     /**
169      * Enables/disables {@link LocalContext local} object pooling.
170      *
171      * @param enabled <code>true</code> if object pooling is locally enabled;
172      * <code>false</code> otherwise.
173      * @see #enter
174      */

175     public static void setEnabled(boolean enabled) {
176         ENABLED.set(enabled ? TRUE : FALSE);
177     }
178
179     private static final Boolean JavaDoc TRUE = new Boolean JavaDoc(true); // CLDC 1.0
180

181     private static final Boolean JavaDoc FALSE = new Boolean JavaDoc(false); // CLDC 1.0
182

183     /**
184      * Indicates if object pooling is {@link LocalContext locally} enabled
185      * (default <code>true</code>).
186      *
187      * @return <code>true</code> if object pooling is locally enabled;
188      * <code>false</code> otherwise.
189      * @see #enter
190      */

191     public static boolean isEnabled() {
192         return ((Boolean JavaDoc) ENABLED.get()).booleanValue();
193     }
194
195     /**
196      * Enters a {@link PoolContext} possibly recycled.
197      * The new pool context is enabled/disabled based upon
198      * the local {@link #isEnabled()} status.
199      */

200     public static void enter() {
201         PoolContext ctx = (PoolContext) FACTORY.object();
202         ctx._isInternal = true;
203         ctx._isEnabled = PoolContext.isEnabled();
204         Context.enter(ctx);
205     }
206     private transient boolean _isInternal;
207
208     /**
209      * Exits and recycles the current {@link PoolContext}.
210      *
211      * @throws UnsupportedOperationException if the current context
212      * has not been entered using PoolContext.enter() (no parameter).
213      */

214     public static void exit() {
215         PoolContext ctx = (PoolContext) Context.current();
216         if (!ctx._isInternal) throw new UnsupportedOperationException JavaDoc
217            ("The context to exit must be specified");
218         ctx._isInternal = false;
219         Context.exitNoCheck(ctx);
220         FACTORY.recycle(ctx);
221     }
222
223     /**
224      * Clears this context (pool objects can then be garbage collected).
225      */

226     public void clear() {
227         for (int i=0; i < _allPools.size(); i++) {
228             ((LocalPools) _allPools.get(i)).clear();
229         }
230     }
231
232     /**
233      * Returns the textual representation of this context (for each factory
234      * the size of the pool).
235      */

236     public Text toText() {
237         return _allPools.toText();
238     }
239
240     // Implements Context abstract method.
241
protected void enterAction() {
242         Context outer = this.getOuter();
243         outer.getLocalPools().deactivatePools();
244         this.getLocalPools().activatePools();
245     }
246
247     // Implements Context abstract method.
248
protected void exitAction() {
249         // Resets all pools (the are not used any more).
250
if (_isEnabled) {
251            for (int i=0; i < _allPools.size(); i++) {
252                ((LocalPools) _allPools.get(i)).reset();
253            }
254         }
255         this.getLocalPools().deactivatePools();
256         Context outer = this.getOuter();
257         outer.getLocalPools().activatePools();
258     }
259
260     // Overrides.
261
final LocalPools getLocalPools() {
262         return _isEnabled ? (LocalPools) _localPools.get() :
263             Context.ROOT.getLocalPools();
264     }
265
266     /**
267      * <p> This class encapsulates a reference allocated on the current stack
268      * when executing in {@link PoolContext}. The reachability level of a
269      * stack reference is the scope of the {@link PoolContext} in which it
270      * has been {@link #newInstance created}.</p>
271      *
272      * <p> Stack references are automatically cleared based upon their
273      * reachability level like any <code>java.lang.ref.Reference</code>.
274      * In other words, stack references are automatically cleared when exiting
275      * the {@link PoolContext} where they have been factory produced.</p>
276      *
277      * <p> Stack references are typically used by functions having more than one
278      * return value to avoid creating new objects on the heap. For example:[code]
279      * // Returns both the position and its status.
280      * public Coordinates getPosition(Reference<Status> status) {
281      * ...
282      * }
283      * ...
284      * PoolContext.Reference<Status> statusRef = PoolContext.Reference.newInstance(); // On the stack.
285      * Coordinates position = getPosition(status);
286      * Status status = statusRef.get();
287      * statusRef.recycle(); // Immediate recycling (optional).
288      * if (status == ACCURATE) ...[/code]
289      * See also {@link ConcurrentContext} for usage examples.</p>
290      *
291      * @author <a HREF="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
292      * @version 3.4, July 3, 2005
293      */

294     public static final class Reference/*<T>*/extends RealtimeObject implements
295             javolution.lang.Reference/*<T>*/{
296
297         /**
298          * Holds the factory.
299          */

300         private static final Factory FACTORY = new Factory() {
301             protected Object JavaDoc create() {
302                 return new Reference();
303             }
304
305             protected void cleanup(Object JavaDoc obj) {
306                 ((Reference) obj)._value = null;
307             }
308         };
309
310         /**
311          * Holds the reference value.
312          */

313         private Object JavaDoc/*{T}*/_value;
314
315         /**
316          * Default constructor (private, instances should be created using
317          * factories).
318          */

319         private Reference() {
320         }
321
322         /**
323          * Returns a new stack reference instance allocated on the current stack
324          * when executing in {@link PoolContext}.
325          *
326          * @return a local reference object.
327          */

328         public static/*<T>*/Reference /*<T>*/newInstance() {
329             return (Reference) FACTORY.object();
330         }
331
332         /**
333          * Recycles this reference immediately regardless if the current
334          * thread is in a pool context or a heap context. The value held
335          * by this reference is automatically cleared.
336          */

337         public void recycle() {
338             FACTORY.recycle(this);
339         }
340
341         /**
342          * Returns the text representation of the current value of this
343          * reference.
344          *
345          * @return <code>Text.valueOf(this.get())</code>
346          */

347         public Text toText() {
348             return Text.valueOf(this.get());
349         }
350
351         // Implements Reference interface.
352
public Object JavaDoc/*{T}*/get() {
353             return _value;
354         }
355
356         // Implements Reference interface.
357
public void set(Object JavaDoc/*{T}*/value) {
358             _value = value;
359         }
360     }
361
362 }
Popular Tags