直接实例化饿汉式(简介直观)
package test; /** * 饿汉式: * 直接创建实例对象,不管你是否需要这个对象都会创建 * 1.构造器私有化 * 2.自行创建,并且用静态变量保存 * 3.向外提供这个实例 * 4.强调这是一个单例,我们可以用final修饰 * @author asus * */ public class Singleton1 { public static final Singleton1 INSTANCE = new Singleton1(); private Singleton1() { } }
枚举式(最简洁)
package test; /** * 枚举类型:表示该类的对象是有限的几个 * 我们可以限定为一个,就成了单例 * @author asus * */ public enum Singleton2 { INSTANCE }
静态代码块饿汉式(适合复杂实例化)
package test; public class Singleton3 { public static final Singleton3 INSTANCE; static { INSTANCE=new Singleton3(); } private Singleton3() { } }
package test; /** * 懒汉式: * 延迟创建这个实例对象 * 1.构造器私有化 * 2.用一个静态变量保存这个唯一的实例 * 3.提供一个静态方法,获取这个实例对象 * @author asus * */ public class Singlenton4 { private static Singlenton4 instance; private Singlenton4() { } public static Singlenton4 getInstance() { if(instance==null) { instance=new Singlenton4(); } return instance; } }
发现有线程安全问题
package test; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class TestSingleton4 { public static void main(String[] args)throws Exception { /*Singlenton4 s1=Singlenton4.getInstance(); Singlenton4 s2=Singlenton4.getInstance(); System.out.println(s1==s2); System.out.println(s1); System.out.println(s2);*/ Callable<Singlenton4> c= new Callable<Singlenton4>() { @Override public Singlenton4 call() throws Exception{ return Singlenton4.getInstance(); } }; ExecutorService es=Executors.newFixedThreadPool(2); Future<Singlenton4>f1=es.submit(c); Future<Singlenton4>f2=es.submit(c); Singlenton4 s1= f1.get(); Singlenton4 s2= f1.get(); System.out.println(s1==s2); System.out.println(s1); System.out.println(s2); es.shutdown(); } }
//代码加锁防止线程问题
package test; public class Singleton5 { private static Singleton5 instance; private Singleton5() { } public static Singleton5 getInstance() { synchronized (Singleton5.class) { if(instance==null) { try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO: handle exception e.printStackTrace(); } instance=new Singleton5(); } } return instance; } }
package test; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class TestSingleton4 { public static void main(String[] args)throws Exception { /*Singlenton4 s1=Singlenton4.getInstance(); Singlenton4 s2=Singlenton4.getInstance(); System.out.println(s1==s2); System.out.println(s1); System.out.println(s2);*/ Callable<Singleton5> c= new Callable<Singleton5>() { @Override public Singleton5 call() throws Exception{ return Singleton5.getInstance(); } }; ExecutorService es=Executors.newFixedThreadPool(2); Future<Singleton5>f1=es.submit(c); Future<Singleton5>f2=es.submit(c); Singleton5 s1= f1.get(); Singleton5 s2= f1.get(); System.out.println(s1==s2); System.out.println(s1); System.out.println(s2); es.shutdown(); } }
加一个if提升效率,只有第一次线程进入时候才加线程锁
另一种安全简洁的创建方法
package test; /** * 在内部类被加载和初始化时,才创建INSTANCE实例对象。 * 静态内部类不会自动随着外部类的加载和初始化而初始化,他是要单独去加载和初始化的。 * 因为是在内部类加载和初始化时创建的,所以是线程安全的的 * @author asus * */ public class Singleton6 { private Singleton6() { } private static class Inner{ private static final Singleton6 INSTANCE=new Singleton6(); } public static Singleton6 getInner() { return Inner.INSTANCE; } }
如果是饿汉式,枚举形式最简单
如果是懒汉式,静态内部类形式最简单