/* * Javolution - Java(TM) Solution for Real-Time and Embedded Systems * Copyright (C) 2006 - Javolution (http://javolution.org/) * All rights reserved. * * Permission to use, copy, modify, and distribute this software is * freely granted, provided that this notice is preserved. */ package javolution.context; import java.lang.ThreadLocal; import javolution.util.FastMap; import javolution.util.FastTable; /** * <p> This class represents the default allocator context. Allocations are * performed using the <code>new</code> keyword and explicit object * {@link ObjectFactory#recycle(Object) recycling} is supported:[code] * char[] buffer = ArrayFactory.CHARS_FACTORY.array(4098); // Possibly recycled. * while (reader.read(buffer) > 0) { ... } * ArrayFactory.CHARS_FACTORY.recycle(buffer); // Explicit recycling. * [/code]</p> * * <p> It should be noted that object recycling is performed on a thread basis * (for performance reasons) and should only be performed if the object * has been factory produced by the same thread doing the recycling. * It is usually not a problem because recycling is done for temporary * objects within the same method. For example:[code] * public String toString() { * TextBuilder tmp = TextBuilder.newInstance(); // Calls ObjectFactory.object() * try { * tmp.append(...); * ... * return tmp.toString(); * } finally { * TextBuilder.recycle(tmp); // Calls ObjectFactory.recycle(...) * } * }[/code] * If allocation/recycling is performed by different threads then * {@link PoolContext} should be employed.</p> * * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a> * @version 5.3, March 19, 2009 */ public class HeapContext extends AllocatorContext { /** * Holds the factory to allocator mapping (per thread). */ private static final ThreadLocal FACTORY_TO_ALLOCATOR = new ThreadLocal() { protected Object initialValue() { return new FastMap(); } }; /** * Holds the allocators which have been activated (per thread). */ private static final ThreadLocal ACTIVE_ALLOCATORS = new ThreadLocal() { protected Object initialValue() { return new FastTable(); } }; /** * Enters a heap context. */ public static void enter() { Context.enter(HeapContext.class); } /** * Exits the current heap context. * * @throws ClassCastException if the context is not a heap context. */ public static void exit() { Context.exit(HeapContext.class); } /** * Default constructor. */ public HeapContext() { } // Overrides. protected void deactivate() { FastTable allocators = (FastTable) ACTIVE_ALLOCATORS.get(); for (int i = 0, n = allocators.size(); i < n;) { ((Allocator) allocators.get(i++)).user = null; } allocators.clear(); } // Overrides. protected Allocator getAllocator(ObjectFactory factory) { final FastMap factoryToAllocator = (FastMap) FACTORY_TO_ALLOCATOR.get(); HeapAllocator allocator = (HeapAllocator) factoryToAllocator.get(factory); if (allocator == null) { allocator = new HeapAllocator(factory); factoryToAllocator.put(factory, allocator); } if (allocator.user == null) { // Activate. allocator.user = Thread.currentThread(); FastTable activeAllocators = (FastTable) ACTIVE_ALLOCATORS.get(); activeAllocators.add(allocator); } return allocator; } // Overrides. protected void enterAction() { getOuter().getAllocatorContext().deactivate(); } // Overrides. protected void exitAction() { this.deactivate(); } // Holds heap allocator implementation. private static final class HeapAllocator extends Allocator { private final ObjectFactory _factory; private final FastTable _recycled = new FastTable(); public HeapAllocator(ObjectFactory factory) { _factory = factory; } protected Object allocate() { return _recycled.isEmpty() ? _factory.create() : _recycled.removeLast(); } protected void recycle(Object object) { if (_factory.doCleanup()) _factory.cleanup(object); _recycled.addLast(object); } public String toString() { return "Heap allocator for " + _factory.getClass(); } } }