Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / February 2007

Tip: Looking for answers? Try searching our database.

SingletonHolder reinvented.

Thread view: 
Andrey Ryabov - 12 Feb 2007 14:16 GMT
Don't blame me I reinvent a wheel again...

I understend this subject was discussed many times.
but I would like to know what do you think about my implementation.

package ru.m12h.utils;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.Callable;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicReference;

public class SingletonHolder<T> implements Callable<T> {
    private AtomicReference<T> _instance = new AtomicReference<T>();
    private AtomicReference<FutureTask<T>> _future = new
AtomicReference<FutureTask<T>>();
    private Callable<T> _callable;

    public SingletonHolder() {
    }

    public SingletonHolder(Callable<T> _callable) {
        this._callable = _callable;
    }

    public T get() {
        try {
            T result = _instance.get();
            if (result != null) {
                return result;
            }
            if (_future.compareAndSet(null, new FutureTask<T>(_callable !=
null ? _callable : this))) {
                _future.get().run();
            }
            result = _future.get().get();
            if (result == null) {
                throw new IllegalStateException();
            }
            _instance.compareAndSet(null, result);
            return result;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("Thread interrupted during lazy
initialization.", e);
        } catch (ExecutionException e) {
            throw new RuntimeException("Exception during lazy initialization.",
e.getCause());
        }
    }

    public T call() throws Exception {
        throw new IllegalStateException("The call() method is not
implemented");
    }

       //
    // Test SingletonHolder ...
       //
    public static SingletonHolder<String> holder = new
SingletonHolder<String>() {
        public String call() throws Exception {
            return "Singleton value is created from thread: " +
Thread.currentThread().getName();
        }
    };

    public static void main(String[] args) {
        int count = 10;
        final CyclicBarrier barrier = new CyclicBarrier(count);
        for (int i = 0; i < count; i++ ) {
            new Thread() {
                public void run() {
                    try {
                        barrier.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                    System.out.printf("Thread %s, time: %d, got value [%s]%n",
                            Thread.currentThread().getName(),
                            System.currentTimeMillis(),
                            holder.get());
                }
            }.start();
        }
    }
}

The major advantage of this implementation against the following:

public class Singleton {
 static class SingletonHolder {
   static Singleton instance = new Singleton();
 }

 public static Singleton getInstance() {
   return SingletonHolder.instance;
 }
}

is that I can resent and re-initialize value of singleton I case, for
example, of redeploy or smth.
It's important for me to be able to resent and re-initialize singleton
object.
Andrey Ryabov - 12 Feb 2007 15:55 GMT
Just simplified version:

public class SingletonHolder<T> implements Callable<T> {
    private AtomicReference<T> _instance = new AtomicReference<T>();
    private AtomicReference<FutureTask<T>> _future = new
AtomicReference<FutureTask<T>>();

    public T get() {
        try {
            T result = _instance.get();
            if (result != null) {
                return result; // Return value if it has already been initialized.
            }
            if (_future.compareAndSet(null, new FutureTask<T>(this))) {  //
create and try to set to _future
                _future.get().run();  // run the task if previous operation
succeed, executed only once!
            }
            result = _future.get().get(); // get result of execution..
            if (result == null) {
                throw new IllegalStateException(...); // It must not be null
            }
            _instance.compareAndSet(null, result); // set only if it was not
set already
            return result;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException(...);
        } catch (ExecutionException e) {
            throw new RuntimeException(...);
        }
    }

       // This method is to be overridden by subclasses.
    public T call() throws Exception {
        throw new IllegalStateException("call is not implemented");
    }
}
Daniel Pitts - 12 Feb 2007 21:03 GMT
> Just simplified version:
>
[quoted text clipped - 35 lines]
>
> }

What's wrong with this approach:

import java.util.concurrent.Future;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class SafeSingletonFactory<T> {
   private T instance;
   final Future<T> factory;

   public SafeSingletonFactory(Callable<T> factory) {
       this.factory = new FutureTask<T>(factory);
   }

   public T get() throws InterruptedException {
       try {
           return instance == null ? instance = factory.get() :
instance;
       } catch (InterruptedException e) {
           throw e;
       } catch (ExecutionException e) {
           if (e.getCause() instanceof Error) {
               throw (Error)e.getCause();
           }
           if (e.getCause() instanceof RuntimeException) {
               throw (RuntimeException)e.getCause();
           }
           throw new RuntimeException("Exception while initializing
singleton.", e.getCause());
       }
   }
}

This way, you don't have to worry about:
1. Thread safety and synchronization (delegated to FutureTask.get())
2. Extending your singleton class.  One class can have many
SafeSingletonFactory<T> instances.
3. atomic operations (again, delgated to FutureTask.get());

So, to use in a Static Singleton Factory Method (which IMHO is a bad
idea to use, but seems to be the common idiom used for singletons:

public class MySingleton {
   public final static SafeSingletonFactory<MySingleton> instance =
            new SafeSingletonFactory<MySingleton>(new
Callable<MySingleton>() {
       public MySingleton call() {
           return new MySingleton();
       }
   }
   private MySingleton() {
   }
}

Thus, you can call MySingleton.instance.get() safely from anywhere,
without too much overhead.

Actually, you could probably just use a Future<MySingleton> instance;
but it can be prematurely cancled by client code, and client code has
more exception handling to do.

I have to say though, in my experience, most Singleton patterns can be
refactored into Dependency Injection with a lot of benefit to the
overal program design.
Andrey Ryabov - 13 Feb 2007 10:00 GMT
> What's wrong with this approach:
>
[quoted text clipped - 12 lines]
>
>     public T get() throws InterruptedException {
Declaring InterruptedException you doom users to handle it every time
they access you singleton...
it will be quite inconvenient..

>         try {
>             return instance == null ? instance = factory.get() :
> instance;
>         } catch (InterruptedException e) {
>             throw e;

what's the point rethorwing this exception?

>         } catch (ExecutionException e) {
>             if (e.getCause() instanceof Error) {
[quoted text clipped - 9 lines]
>
> }

Have you tried to run it?
I think it wont work.. FutureTask.run() method must be called, without
it FutureTask.get() won't work!

> This way, you don't have to worry about:
> 1. Thread safety and synchronization (delegated to FutureTask.get())
[quoted text clipped - 24 lines]
> but it can be prematurely cancled by client code, and client code has
> more exception handling to do.

> I have to say though, in my experience, most Singleton patterns can be
> refactored into Dependency Injection with a lot of benefit to the
> overal program design.

Singletons that could be refactored into some sort of IoC are NOT TURE
singletons. Dependency injection is not a way of keeping and managing
objects, it's a way of getting access to them (in sense OOP).
True singletons are unavoidable. Have a look inside implementation of
your favorite IoC container, I'm quite sure you'll find them there:).
Daniel Pitts - 13 Feb 2007 19:42 GMT
> > What's wrong with this approach:
>
[quoted text clipped - 81 lines]
> True singletons are unavoidable. Have a look inside implementation of
> your favorite IoC container, I'm quite sure you'll find them there:).

Improper handling of InterruptedException can lead to severe problems.

If you have an immutable singleton, then this is an acceptible idiom:

class MySingletonHolder {
   private final static MySingleton instance = new MySignleton();
   public static MySingleton get() {
       return instance;
   }
}

It is thread-safe and lazily loaded.
Andrey Ryabov - 14 Feb 2007 08:34 GMT
On Feb 13, 10:42 pm, "Daniel Pitts" <googlegrou...@coloraura.com>
wrote:

> > > What's wrong with this approach:
>
[quoted text clipped - 81 lines]
> > True singletons are unavoidable. Have a look inside implementation of
> > your favorite IoC container, I'm quite sure you'll find them there:).

> Improper handling of InterruptedException can lead to severe problems.

I suggest the following way to handle InterruptedException in this
case

catch (InterruptedException e) {
    Thread.currentThread().interrupt();           // Set interrupt
flag again
     throw new RuntimeException(...);             // and wrapped
exception.
}

Is something wrong in this approach?

> If you have an immutable singleton, then this is an acceptible idiom:
>
[quoted text clipped - 7 lines]
>
> It is thread-safe and lazily loaded.

Yes.. but  I have to be able reinitialize my singleton therefore this
idiom is not acceptable for me.
Daniel Pitts - 14 Feb 2007 19:14 GMT
> On Feb 13, 10:42 pm, "Daniel Pitts" <googlegrou...@coloraura.com>
> wrote:
[quoted text clipped - 114 lines]
> Yes.. but  I have to be able reinitialize my singleton therefore this
> idiom is not acceptable for me.

If you have to reinitialize it, then its not a singleton. It is either
a pooled object and/or should be injected.

Also, you need to synchronize if the state can change.

It really sounds to me like you're pushing the square peg called
"Singleton" into a round hole.
Andrey Ryabov - 15 Feb 2007 09:17 GMT
> > Yes.. but  I have to be able reinitialize my singleton therefore this
> > idiom is not acceptable for me.
[quoted text clipped - 6 lines]
> It really sounds to me like you're pushing the square peg called
> "Singleton" into a round hole.

Imagine, for example, logging service implemented as singleton. This
service has complex logic and depends on other services: it stores
records to database to remote network server and so on... Then an
application is going to shutdown, it closes connections to database
and remote server but it still uses logging service that is it's turn
uses connections that has already been closed. To avoid this
implementation of logging service can be substituted by another that
don't depends on already stoped services (NullObject or very simple
implementation).
You would suggest me implement logging service that checks wheder or
not application is going to be shotdown. Bug it is possible only is
very rare cases. The number of implementations of singleton services
could not be known, they can substitute each other during program
runtime and should be lazy initialized.

I'm not against the dependency injection but it is not a rescue in
some cases it has a lot of drawbacks, on of them is lack of dynamic
flexibility.

For example:
If service A depends on service B it receive reference to
implementatin of service B  (B_impl) during creation. What to do if we
need to change implementation of service B from B_impl to B_imple2 ?.
With classical dependency injection it very hard to achieve this
because implemetation of A can cache reference to B and it will be
imposible to re-inject it!. The more flexible way to access services
is to use some sort of Service Locator it is also could becombined
with Dipendency Injection.
Daniel Pitts - 15 Feb 2007 18:20 GMT
>  > > Yes.. but  I have to be able reinitialize my singleton therefore
> this
[quoted text clipped - 37 lines]
> is to use some sort of Service Locator it is also could becombined
> with Dipendency Injection.

One solution:

Inject a single AtomicReference<B> instance into everything that needs
the service provided by B.

When the implementation of B used needs to change, update the atomic
reference.

Or, to "hide" this atomic reference:

class BDelegate implements B {
  private final AtomicReference<B> ref = new AtomicReference<B>();
  public BDelegate(B impl) {
     ref.set(impl);
  }

  public void changeImpl(B newImpl) {
     ref.set(newImpl);
  }

  // delegate B implementation to ref.get();
}

This also gives you the change to make "changeImpl" thread-safe.  If
someone is in the middle of a multi-step action with the existing
previous B object, you can add proper synchronization to ensure that
the new impl isn't changed before it should be.
Alex Hunsley - 12 Feb 2007 19:41 GMT
> Don't blame me I reinvent a wheel again...
>
> I understend this subject was discussed many times.
> but I would like to know what do you think about my implementation.
[snip]

> is that I can resent and re-initialize value of singleton I case,

"in" case, surely?

> for
> example, of redeploy or smth.

What is "smth"?

> It's important for me to be able to resent

Don't hate your objects. Learn to love them.

> and re-initialize singleton
> object.


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.