什么是单例模式?
简单来说就是一个类只允许创建一个实例对象
为什么要使用单例模式?
在业务开发中,有些数据在开发中只保存一份,就比较适合设计成单例模式,比如配置信息、唯一ID递增号码生成器,同样我们还可以使用单例模式解决资源冲突问题
如何实现一个单例模式?
单例模式主要由下面几个方面:
- private修饰的构造方法,这样可以避免外部通过new创建对象
- 对象创建的线程安全问题
- 支不支持延迟加载,就是什么时候创建实例对象
- getInstance()的加锁问题,怎么加锁
常见单例模式写法
1、饿汉式
类加载过程中,instance就已经创建了,所以饿汉式实例的创建是线程安全的,缺点是不支持延迟加载,因为一开始实例就创建了,如果不用就浪费了
public class Singleton {
private static final Singleton instance = new Singleton();
//private修饰限制出现多个对象
private Singleton(){
}
//获得实例对象的方法
public static Singleton getInstance(){
return Sinleton.instance;
}
//其他方法
public void method() {
}
}
2、懒汉式
懒汉式支持延迟加载,但是加了synchronize锁,性能会下降,不支持高并发
public class Singleton {
private static Singleton instance = null;
priviate Singleton(){
}
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
//其他方法
public void method() {
}
}
3、双重检测
双重检测有两次instance判空操作,都用什么作用?
第一次:在synchronized同步块外部,作用是提高性能,如果没有这步,每次执行getInstance()方法,都会执行synchronized同步块的内容,第一次的判断目的就是为了减少synchronized同步块的执行次数
第二次:在synchronized同步块内部,这此检测是否为了防止当多线程下进入第一次if判断后,产生多次创建单例对象
public class Singlrton {
private static volatile Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
if(instance == null) {
synchronized(Singleton.class) {
if(instance == null) {
instance = new Singleton;
}
}
}
return instance;
}
//其他方法
public void method() {
}
}
4、静态内部类
这种方式线程安全,支持延迟加载,当外部Singleton外部类加载时,创建单例对象的静态内部类不会被加载,只有调用getInstance方法时,静态内部类才会被加载,JVM保证了instance的唯一性和创建过程的线程安全性
public class Singleton {
private Singleton (){
}
private static class SingletonHolder {
private static final Singleton instance = new Singleton();
}
public static Singlrton getInstance() {
return SinletonHolder.instance;
}
//其他方法
public void method() {
}
}
5、枚举类
通过Java 枚举类型本身的特性,保证了实例创建的线程安全性和实例的唯一性
public enum Sinleton {
instance;
//其他方法
public void method() {
}
}
总结
- 饿汉式
- 懒汉式
- 双重检测
- 静态内部类
- 枚举类
参考资料: