5

I am facing a problem with my singleton when used across multiple class loaders. E.g Singleton accessed by multiple EJBs. Is there any way to create a singleton which has only one instance across all class loader?

I am looking for pure java solution either using custom class loader or some other way.

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
rjoshi
  • 1,645
  • 1
  • 20
  • 31
  • maybe that helps: http://stackoverflow.com/questions/70689/efficient-way-to-implement-singleton-pattern-in-java – Chris Sep 29 '09 at 21:10
  • What app server are you using? – Taylor Leese Sep 29 '09 at 21:12
  • 4
    Are your PR'ing your own blog? That's what your profile says. So "I found a link" is really "I wrote that post". – ChssPly76 Sep 29 '09 at 21:12
  • possibly... it remains a valid question, though, regardless of the motivation for asking it. – skaffman Sep 29 '09 at 21:15
  • I am just trying to prove the point that I couldn't create a absolute singleton based on someone's article "Absolute Singleton". If that is the issues, I can remove the link. – rjoshi Sep 29 '09 at 21:16
  • I am using Glassfish App server and OpenESB as Enterprise Service Bus. If you see the link, first instance is created by POJO-SE (which is a binding component in OpenESB) and 2nd instance is created by EJB. – rjoshi Sep 29 '09 at 21:17
  • Change it from "I've foud a link [your blog]" to "I found a link [the link you found] and I wrote this with my findings [your blog]" until then I'm voting to have this closed. – OscarRyz Sep 29 '09 at 21:25
  • Deleted the link to my blog which was clarifying the problem of multiple class loaders to keep ChssPly76 and Oscar Reyes happy. – rjoshi Sep 29 '09 at 21:36
  • I'm happy now, and up voting this question – OscarRyz Sep 29 '09 at 21:46
  • http://surguy.net/articles/communication-across-classloaders.xml Refer to this link – madhav Apr 24 '10 at 15:19

4 Answers4

5

The only way would be to make your singleton class be loaded by a single classloader - put that jar file in the bootclasspath, for example.

A static variable is inherently tied to the classloader which loaded the class containing that variable. It's just the way it works. If you need absolutely one instance, you need that class to only be loaded by one classloader.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • We use Glassfish App server and OpenESB as Enterrprise service bus. This singleton (a wrapper to JCS Cache to store Ldap Search results) is part of the common library which is shared among multiple binding components and EJB's. – rjoshi Sep 29 '09 at 21:20
  • @rjoshi: And is the singleton being loaded in multiple classloaders, and can you avoid that? If the class is always going to be in multiple classloaders, I can't see how you can avoid it not being a "proper" singleton. – Jon Skeet Sep 29 '09 at 23:47
  • And also assure that you are careful with serialization/deserialization. Best practice is probably to avoid allowing your singleton to be serializable. – CPerkins Sep 29 '09 at 23:58
  • @Pascal: it was a mistake to accept the answer. so I have deleted it. – rjoshi Oct 03 '09 at 00:41
5

JavaEE app servers generally solve this problem by setting up the singleton as a "service", the exact definition and configuration of which depends on the appserver in question.

For example, in JBoss you could use a xyz-service.xml descriptor to set up a singleton object that hangs off the JNDI or JMX tree, and your application components (e.g. your EJBs) would fetch the singleton from the tree. That protects you to some extent from the underlying classloader semantics.

skaffman
  • 398,947
  • 96
  • 818
  • 769
  • We use Glassfish App server and OpenESB as Enterrprise service bus. This singleton is part of the common library which is shared among multiple binding components and EJB's. – rjoshi Sep 29 '09 at 21:19
  • 2
    OK, so find out how to create a JMX service in Glassfish, and connect to that service from your components. – skaffman Sep 29 '09 at 21:24
  • I googled but couldn't find anything except support of EJB3.1 with singleton feature in Glassfish V3. but we use EJB3 with Glassfish 2.1GA. – rjoshi Sep 29 '09 at 21:39
3

J2EE is designed with clustering in mind, so any designs that it supports are going to have to work with multiple JVM's. I take it from your question that you aren't concerned about a clustered environment, so a simple insertion into JNDI on your app server should do it. In Glassfish, that is called a lifecycle listener. After the startup even, insert your singleton into JNDI, and then have everything else do a JNDI lookup to find it.

Note that GlassFish could still mess you up here, in that it could serialize the class to JNDI causing you to get different instances. I doubt it actually does this within one JVM, but you won't know until you try it.

The real bottom line answer is that J2EE is hostile to a global true singleton, and the J2EE way around the problem is to rethink the solution. Something like a database to hold values or some other external service that can ensure that only one instance of the data (even if multiple instances of objects representing the data) exists is the J2EE way.

Yishai
  • 90,445
  • 31
  • 189
  • 263
  • I am using this singleton to store the ldap cache. I am wondering how other developers are solving this issues? – rjoshi Sep 29 '09 at 21:56
  • 1
    rjoshi, I would ask that as a seperate question with some more technical details, but it seems to me that you don't need it to be truely global. Put it in JNDI, and if a given lookup happens twice, so be it. – Yishai Sep 30 '09 at 01:11
  • @Yishai: thx. for you suggestion. I will try it out and let you know. I was trying to avoid the JNDI/EJB wrapper and resolve using classloader hack but I guess that's the only way.. – rjoshi Sep 30 '09 at 13:05
0

To achieve TRUE Singleton, you have follow below guidelines:

  1. Make your class as final. Others can't sub-class it and create one more instance
  2. Make your Singleton instance as private static final
  3. Provide private constructor and public getInstance() method.
  4. Make sure that this Singleton class is loaded by one ClassLoader only
  5. override readResolve() method and return same instance without creating new instance in de-Serialization process.

Sample code:

final class  LazySingleton {
    private LazySingleton() {}
    public static LazySingleton getInstance() {
        return LazyHolder.INSTANCE;
    }
    private static class LazyHolder {
        private static final LazySingleton INSTANCE = new LazySingleton();
    }
    private Object readResolve()  {
        return LazyHolder.INSTANCE;
    }
}

Refer to below SE question for more details:

What is an efficient way to implement a singleton pattern in Java?

Community
  • 1
  • 1
Ravindra babu
  • 37,698
  • 11
  • 250
  • 211