单例模式八种实现方式
1、饿汉单例
/** * 饿汉单例 * 优点:简单、线程安全 * 缺点:浪费内存(我们的单例对象数量不可控的时候,可能会造成内存浪费) */ public class HungraySingleton { //类被夹在时,单例对象就已经被创建 private static final HungraySingleton instance = new HungraySingleton(); //空参构造器 public HungraySingleton() { } //提供全局访问点 public final static HungraySingleton getInstance(){ return instance; } }
2、 饿汉单例-静态代码块(装逼)
/** * 饿汉静态代码块 */ public class HungrayStaticSingleton { private static final HungrayStaticSingleton instance; static { instance = new HungrayStaticSingleton(); } public HungrayStaticSingleton() { } public static HungrayStaticSingleton getInstance(){ return instance; } }
3、 懒汉单例
/** * 懒汉式 * 优点:节省资源,性能更高 * 缺点:线程不安全 */ public class LazySingleton { private static LazySingleton instance; public LazySingleton() { } /** * 添加synchronized是可以保障线程安全,但是性能会下降 */ public synchronized static final LazySingleton getInstance(){ if (instance == null){ instance = new LazySingleton(); } return instance; } }
4、懒汉单例-双重校验锁
/** * 懒汉双重检查锁 * 优点:性能高,线程安全,避免内存浪费 * 缺点:不优雅 * */ public class LazyDoubleCheckSingleton { private volatile static LazyDoubleCheckSingleton instance; public LazyDoubleCheckSingleton() { } public static final LazyDoubleCheckSingleton getInstance() { //双重校验锁 控制是否加锁,主要控制第一次 if (instance == null) { synchronized (LazyDoubleCheckSingleton.class) { //控制是否创建对象 if (instance == null) { instance = new LazyDoubleCheckSingleton(); //存在指令重排序 需要加volatile关键字 } } } return instance; } }
5、懒汉-静态内部类
** * 懒汉,静态内部类 * 优点:性能高,线程安全,避免内存浪费 * 缺点:不优雅了 */ public class LazyStaticInnerClassSingleton { //巧妙的利用了Java的语法,利用了类加载机制,内部类都是在第一次使用的时候才会被加载, // 发生在线程创建之前,一定是线程安全的 public LazyStaticInnerClassSingleton() { //防止有不听话人员通过反射创建对象,但是代码就变得不优雅了 if (LazyHoldler.instance != null) { throw new RuntimeException("不能非法创建单例对象"); } } public static final LazyStaticInnerClassSingleton getInstance() { return LazyHoldler.instance; } private final static class LazyHoldler { private static final LazyStaticInnerClassSingleton instance = new LazyStaticInnerClassSingleton(); } }
6、枚举单例 (最优雅的单例实现模式)
/** * 枚举可以归到饿汉单例中 * **************************推荐用枚举实现单例****************************** * 最优雅的单例实现模式就是枚举模式。利用枚举的特性,让JVM来帮我们保证线程安全和单一实例的问题。 */ public enum EnumSingleton { INSTANCE; private String s = null; private EnumSingleton() { s = new String(); } public String getInstance() { return s; } }
7、注册式单例
/** * 容器式单例,是枚举式单例的升级 * Spring中的做法,就是这种注册式单例 */ public class ContainerSingleton { public ContainerSingleton() { } private static Map<String, Object> ioc = new ConcurrentHashMap<String, Object>(); public static Object getInstance(String className) { //双重校验锁 判断是否加锁 if (!ioc.containsKey(className)) { synchronized (ioc) { //是否创建对象 if (!ioc.containsKey(className)) { Object obj = null; try { obj = Class.forName(className).newInstance(); ioc.put(className, obj); } catch (Exception e) { } return obj; } else { return ioc.get(className); } } } return ioc.get(className); } }
8、threadLocal实现单例
/** * ThreadLocal 实现单例模式 * 不能保证整个程序唯一; * 可以保证线程唯一; * 每个线程中拿到的实例都是一个; * 不同的线程拿到的实例不是一个; */ public class ThreadLocalSingleton { private static final ThreadLocal<ThreadLocalSingleton> threadLocalInstanceThreadLocal = new ThreadLocal<ThreadLocalSingleton>() { @Override protected ThreadLocalSingleton initialValue() { return new ThreadLocalSingleton(); } }; private ThreadLocalSingleton() { } public static ThreadLocalSingleton getInstance() { return threadLocalInstanceThreadLocal.get(); } }public class ThreadLocalRunnable implements Runnable { public void run() { ThreadLocalSingleton instance =ThreadLocalSingleton.getInstance(); System.out.println(Thread.currentThread().getName() + " : " + instance); } }ThreadLocalSingleton instance = ThreadLocalSingleton.getInstance(); System.out.println(Thread.currentThread().getName() + " : " + instance); instance = ThreadLocalSingleton.getInstance(); System.out.println(Thread.currentThread().getName() + " : " + instance); instance = ThreadLocalSingleton.getInstance(); System.out.println(Thread.currentThread().getName() + " : " + instance); instance = ThreadLocalSingleton.getInstance(); System.out.println(Thread.currentThread().getName() + " : " + instance); instance = ThreadLocalSingleton.getInstance(); System.out.println(Thread.currentThread().getName() + " : " + instance); Thread t1 = new Thread(new ThreadLocalRunnable()); Thread t2 = new Thread(new ThreadLocalRunnable()); t1.start(); t2.start(); System.out.println("Program End");执行结果
main : com.pa.designMode.singleton.ThreadLocalSingleton@65ab7765
main : com.pa.designMode.singleton.ThreadLocalSingleton@65ab7765
main : com.pa.designMode.singleton.ThreadLocalSingleton@65ab7765
main : com.pa.designMode.singleton.ThreadLocalSingleton@65ab7765
main : com.pa.designMode.singleton.ThreadLocalSingleton@65ab7765
Program End
Thread-0 : com.pa.designMode.singleton.ThreadLocalSingleton@2770f418
Thread-1 : com.pa.designMode.singleton.ThreadLocalSingleton@dc7a4fc