For eager-initialization singleton, the simplest way is to use an enum type with only 1 INSTANCE.  The limitation is your enum singleton class cannot extend from a super class.
public enum EnumSingleton implements Calc {
    INSTANCE;

    public int add(int a, int b) {
        return a + b;
    }
}
A traditional, non-enum implementation of eager-initialization singleton is:
public class EagerSingleton {
    private static EagerSingleton instance = new EagerSingleton();

    private EagerSingleton() {}

    public static EagerSingleton getInstance() { return instance; }
} 
A lazy-initialization singleton implemented with double-checked locking (DCL), which works in Java 5 onward:
package test.concurrent;
public final class MySingleton1 {
 private static volatile MySingleton1 instance;

 private MySingleton1() {}

 public static MySingleton1 getInstance() {
   MySingleton1 result = instance;
   if(result == null) {
     synchronized (MySingleton1.class) {
       result = instance;
       if(result == null) {
         instance = result = new MySingleton1();
       }
     }
   }
   return result;
 }
A lazy-initialization singleton implemented with holder idoim (applicable to lazy static field).  The limitation is the instance can only be created with default constructor, and there is no way to pass params from getInstance(...) to the constructor.  In that case, use DCL instead:
package test.concurrent;
public final class MySingleton2 {
 private MySingleton2() {}

 private static class Holder {
   private static final MySingleton2 instance = new MySingleton2();
 }

 public static MySingleton2 getInstance() {
   return Holder.instance;
 }
A main method that spawns multiple threads calling getInstance():
public static void main(String[] args) {
   int numOfThreads = Integer.parseInt(args[0]);
   for(int i = 0; i < numOfThreads; i++) {
     Thread t = new Thread(new Runnable() {
       public void run() {
         System.out.println(MySingleton1.getInstance());
       }
     });
     t.start();
   }
 }
When the same singleton class is loaded by different class loaders, each loader has its own class data. MySingleton1.class loaded by classloader1 is a distinct class from MySingleton1.class loaded by classloader2. Hence multiple instances will be created when calling MySingleton1.getInstance().

To test this scenario, write a servlet that calls MySingleton1.getInstance, and print it. Package the servlet class and MySingleton1 class in test.war, deploy it to appserver. Redeploy the same war in a different context root test2. Invoke the 2 webapp to see if the same instance is printed.

The servlet class:
package test;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

@javax.servlet.annotation.WebServlet(urlPatterns = "/*")
public class TestServlet extends HttpServlet {
 protected void processRequest(HttpServletRequest request, HttpServletResponse response)
 throws ServletException, IOException {
   PrintWriter out = response.getWriter();
   out.println("singleton: " + MySingleton1.getInstance());
 }
 @Override
 protected void doGet(HttpServletRequest request, HttpServletResponse response)
 throws ServletException, IOException {
   processRequest(request, response);
 }
 @Override
 protected void doPost(HttpServletRequest request, HttpServletResponse response)
 throws ServletException, IOException {
   processRequest(request, response);
 }
}
The content of test.war:
WEB-INF/classes/test/MySingleton1$1.class
WEB-INF/classes/test/MySingleton1.class
WEB-INF/classes/test/TestServlet.class
To deploy the webapp to GlassFish:
$ asadmin deploy test.war
$ asadmin deploy --name test2 test.war
$ asadmin list-applications
To run the 2 webapp and notice 2 different instances of MySingleton class are instantiated within the same JVM, one for each webapp:
$ curl http://localhost:8080/test/
singleton: test.MySingleton1@114536a5

$ curl http://localhost:8080/test/
singleton: test.MySingleton1@114536a5

$ curl http://localhost:8080/test2/
singleton: test.MySingleton1@3997ebf6

$ curl http://localhost:8080/test2/
singleton: test.MySingleton1@3997ebf6
2

View comments

Labels
Archive
Popular Posts
Popular Posts
  • Two JVM options are often used to tune JVM heap size: -Xmx for maximum heap size, and -Xms for initial heap size. Here are some common mi...
  • Simple enum . The ; after the last element is optional, when this is the end of enum definition. public enum Color { WHITE, BLACK, RED, ...
  • How to set project classpath in Eclipse and NetBeans are similar: just right-click the project name, choose Properties to bring up the Prope...
  • Let's say I need to spawn multiple threads to do the work, and continue to the next step only after all of them complete. I will need t...
  • This is a sample web.xml based on Servlet 2.5 (part of Java EE 5) that declares common elements. All top-level elements are optional, and c...
  • The default string value for java enum is its face value, or the element name. However, you can customize the string value by overriding toS...
  • Prior to JDK 6, we can check if a string is empty in 2 ways: if(s != null && s.length() == 0) if(("").equals(s)) Checking ...
  • When writing javadocs, IntelliJ automatically adds a closing tag for html elements. For instance, after typing <lt>, it automaticaly a...
  • StringBuilder was introduced in JDK 1.5. What's the difference between StringBuilder and StringBuffer? According to javadoc , StringBu...
  • With array, we can easily declare and initialize it at the same time: String[] favorites = new String[] {"EJB", "JPA", ...
Loading