单例模式有五种写法,分别是
饿汉式
懒汉式
双重检查
静态内部类
枚举
但是饿汉式又分两种静态常量和静态代码块,懒汉式又分三种线程不安全的,线程安全(同步方法),线程安全(同步代码块),所以细分下来一共有八种写法。
1,饿汉式(静态常量)
实现原理是通过一个静态方法返回一个静态实例,代码如下
public class Singleton { private Singleton(){} private final static Singleton singleton = new Singleton(); public static Singleton getInstance(){ return singleton; } }
优点:写法简单,在类加载的时候完成实例化,避免了线程同步问题
缺点:在类加载的时候就完成实例化,如果一直没有用的这个类,就造成了内存的浪费
2,饿汉式(静态代码块)
public class Singleton { private Singleton(){} private static Singleton singleton; static { singleton = new Singleton(); } public static Singleton getInstance(){ return singleton; } }
这种方法跟上面静态常量写法的优缺点是一样的
3,懒汉式(线程不安全)
public class Singleton { private Singleton(){} private static Singleton singleton; public static Singleton getInstance(){ if(singleton == null){ singleton = new Singleton(); } return singleton; } }
优点:不会在你不用的情况下去创建对象
缺点:只能在单线程下使用,多线程情况下if语句中可能多个线程进入,就会创建多个对象
在实际开发中不建议使用
4,懒汉式(线程安全,同步方法)
在上面代码的基础上加一个synchronize关键字
public class Singleton { private Singleton(){} private static Singleton singleton; public static synchronized Singleton getInstance(){ if(singleton == null){ singleton = new Singleton(); } return singleton; } }
优点:解决了线程不安全的问题
缺点:效率太低了,每个线程获取实例的时候,执行getInstance方法都要进行同步
在实际开发中,不推荐使用
5,懒汉式(线程安全,同步代码块)
开起来线程安全,其实还是线程不安全的,依旧会可能又两个线程进入if语句中
public class Singleton { private Singleton(){} private static Singleton singleton; public static Singleton getInstance(){ if(singleton == null){ synchronized (Singleton.class){ singleton = new Singleton(); } } return singleton; } }
实际开发中,不能使用这种方式
6,双重检查
public class Singleton { private Singleton(){} private static volatile Singleton singleton; public static Singleton getInstance(){ if(singleton == null){ synchronized (Singleton.class){ if(singleton == null) { singleton = new Singleton(); } } } return singleton; } }
使用volatile关键字保证可见性和有序性,在同步块外面和里面都进行一次判断,解决了线程安全问题,也解决了懒加载问题
7,静态内部类
采用类加载的机制来保证初始化实例时只有一个线程
静态内部类在Singleton被装载时不会实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonInstance类
类的静态属性只会在第一次加载类的时候初始化,JVM帮我们保证了线程的安全,在类初始化时,别的线程是无法进入的
public class Singleton { private Singleton(){} private static class SingletonInstance{ private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance(){ return SingletonInstance.INSTANCE; } }
优点:保证了线程安全,利用静态内部类的特点实现了懒加载,效率高
8,枚举
enum SingletonEnum{ INSTANCE; }
优点:借助jdk1.5中添加的枚举来实现单例模式。不仅能避免多线程同步的问题,还能防止反序列化重新创建对象
在jdk中哪个地方用到了单例模式呢,RunTime类使用饿汉式实现单例模式