单例模式(Singleton Pattern)是 Java 中最非常常见的设计模式之一属于创建型模式,常用在工具类,所谓单例,就是整个程序有且仅有一个实例。该类负责创建自己的对象,同时确保只有一个对象被创建。
单例模式的特点
- 单例类只能有一个实例
- 单例类必须自己创建自己的唯一实例
- 单例类必须给其他所有对象提供这一实例
- 类构造器私有
下面我们看一下单例模式最常见的实现方式,懒汉模式和饿汉模式的实现方式:
饿汉模式
饿汉模式,就是在类加载时直接创建出单例类,看一下饿汉式的写法:
1 public class Singleton { 2 private static Singleton instance = new Singleton(); 3 private Singleton (){} 4 5 public static Singleton getInstance() { 6 return instance; 7 } 8 }
这就是饿汉式单例模式的写法,它基于 classloader 机制避免了多线程的同步问题,这种方式比较常用,但容易产生垃圾对象,类加载时就初始化,浪费内存;
懒汉模式
顾名思义,只有当单例类被用到的时候才会去创建这个单例类,看一下懒汉式的写法:
1 public class Singleton { 2 private static Singleton instance; 3 private Singleton (){} 4 5 public static Singleton getInstance() { 6 if (instance == null) { 7 instance = new Singleton(); 8 } 9 return instance; 10 } 11 }
这种方式是最基本的实现方式,但这种写法基本不用,因为这是一种线程非安全的写法,试想,如果两个线程同时走到 if (instance == null) 时得到instance都是null,就会创建两个对象也就不再是单例,所以严格意义上它并不算单例模式;
双检锁模式
双检锁模式可以理解为懒汉模式的改进版本,既然懒汉模式是非线程安全的那么最直接的想法就是加锁使之变为线程安全的,写法如下:
1 public class Singleton { 2 private volatile static Singleton singleton; 3 private Singleton (){} 4 public static Singleton getSingleton() { 5 if (singleton == null) { 6 synchronized (Singleton.class) { 7 if (singleton == null) { 8 singleton = new Singleton(); 9 } 10 } 11 } 12 return singleton; 13 } 14 }
双重检查模式,进行了两次的判断,第一次是为了避免不要的实例,第二次是为了进行同步,避免多线程问题。由于singleton=new Singleton()对象的创建在JVM中可能会进行重排序,在多线程访问下存在风险,使用volatile修饰signleton实例变量可以有效解决该问题。
另外,除了以上实现方式外还有静态内部类的方式、静态代码块的方式、枚举的方式也可以实现,就不在写出来了;