Markus A. Markus A. - 3 months ago 23
Java Question

Thread-specific singleton instances

I am looking for a good way to write an instance factory that creates exactly one instance of a class for each thread (in other words: a thread-specific singleton).

Let me add some example code for clarity:

First, an interface that defines a factory in general:

public interface Factory<T> {
public T create();
}


For normal singletons, I can then create an implementation of this interface that wraps another factory:

public class SingletonFactory<T> implements Factory<T> {

private final Factory<T> factory;
private T instance = null;

public SingletonFactory(Factory<T> factory) {
this.factory = factory;
}

@Override
public T create() {
if (instance==null) instance = factory.create();
return instance;
}
}


Basically, the first time that
create()
is called, this call is forwarded to the provided factory to create one instance of the object. This instance is cached and all future calls to
create()
will return that same instance. All I need to do is to make sure that there is only one instance of
SingletonFactory
around per object-type
T
.

Let's say I want to provide exactly one instance of the object per thread: I could do something like this:

public class ThreadSingletonFactory<T> implements Factory<T> {

private final Factory<T> factory;
private final Map<Thread, T> instance;

public ThreadSingletonFactory(Factory<T> factory) {
this.factory = factory;
this.instance = new HashMap<Thread, T>();
}

@Override
public T create() {
Thread thread = Thread.currentThread();
T result = instance.get(thread);
if (result==null) {
result = factory.create();
instance.put(thread, result);
}
return result;
}
}


Now, every time
create()
is called, the class looks up the current thread in its instance map to see if this thread already has an instance created. If not, it creates a fresh one and remembers it.

I see a couple of issues with this naive approach:


  1. HashMap is not thread safe, it might not be an issue since no two threads will ever operate on the same key, but I'm not sure. I could just use
    Collections.synchronizedMap
    to make it thread safe, but I would like to avoid that since it implies tons of synchronizations everywhere which might have a significant performance impact.

  2. If the application doesn't use a thread-pool, but keeps spawning tons and tons of short-lived new threads, the map will grow to potentially enormous size and block a lot of memory with no-longer-needed instances.



I was looking into using a
WeakHashMap
instead to address the second issue, since it allows its entries to be garbage collected once the keys are no longer in use, but I came across two potential issues with that as well:


  1. Looking at the
    OpenJDK Source
    , the freeing of unused keys via
    expungeStaleEntries()
    is initiated every time I call
    get(...)
    or
    put(...)
    and involves potentially multiple synchronized operations, which, again, I would like to avoid for performance reasons.

  2. I am still not sure that I don't also need to wrap the map into a synchronizedMap to make sure I don't run into concurrency issues.



Is there a different solution that preferably does not need to use any
synchronization
(assuming that all implementations of
Factory.create()
are thread-safe)? If it does need to manage concurrency somehow, I would prefer it to do so via the classes in
java.util.concurrent.atomic
.

Answer

As suggested by @JBNizet and @SotiriosDelimanolis, ThreadLocal might do the trick.

I haven't tested it yet, but this might be it then?

public class ThreadSingletonFactory<T> implements Factory<T> {

    private final ThreadLocal<T> instance;

    public ThreadSingletonFactory(final Factory<T> factory) {
        this.instance = new ThreadLocal<T>() {
            @Override
            protected T initialValue() {
                return factory.create();
            }
        };
    }

    @Override
    public T create() {
        return instance.get();
    }
}