单例模式:类只会被实例化一次,每次都是调用同一个对象。
在计算机系统中,还有 Windows 的回收站、操作系统中的文件系统、多线程中的线程池、显卡的驱动程序对象、打印机的后台处理服务、应用程序的日志对象、数据库的连接池、网站的计数器、Web 应用的配置对象、应用程序中的对话框、系统中的缓存等常常被设计成单例。
单例模式有 3 个特点:
- 单例类只有一个实例对象;
- 该单例对象必须由单例类自行创建;
- 单例类对外提供一个访问该单例的全局访问点;
1、懒汉式(效率太低)
/**
* 通过懒汉模式实现单例模式,synchronized同步会大大降低效率
* @author HP
*
*/
public class SingletonLanHan {
private static SingletonLanHan instance;
private SingletonLanHan(){
System.out.println("我是懒汉");
}
//如果不加synchronized就会造成多线程中的不安全
public synchronized static SingletonLanHan getInstance(){
if(instance == null){
instance = new SingletonLanHan();
}
return instance;
}
}
2、饿汉式(基于classloader机制,但不能懒加载)
/**
* 饿汉模式实现单例模式,不能实现懒加载
* 在类加载阶段就进行了实例化
* @author HP
*
*/
public class SingletonEHan {
private static SingletonEHan instance = new SingletonEHan();
private SingletonEHan(){
System.out.println("饿汉创建成功");
}
//静态工厂模式实例化对象
public static SingletonEHan getInstance(){
return instance;
}
}
3、静态内部类实现
/**
* 通过静态内部类实现单例模式,可以实现懒加载
* @author HP
*
*/
public class SingletonInnerClass {
private static class SingletonHolder{
private static final SingletonInnerClass instance = new SingletonInnerClass();
}
public SingletonInnerClass(){
System.out.println("我是通过静态内部类实现");
}
public static SingletonInnerClass getInstance(){
return SingletonHolder.instance;
}
}
4、枚举类实现(最佳方法)
/**
* 通过枚举实现的单例模式
* 不仅能实现多线程的同步
* 还能防止反序列化创建不同的实例
* 目前认为的最佳实现单例模式的方法
* 枚举类内部实现了public static final
* 并默认调用了私有无参构造器
* @author HP
*
*/
public enum SingtonMeiJu {
INSTANCE;
private SingtonMeiJu(){
System.out.println("我是通过枚举实现的");
}
}
5、双重检查锁(DCL)
/**
* 双重检查锁实现单例模式
* @author HP
*
*/
public class SingtonDCL {
//使用volatile防止指令重排序
private volatile static SingtonDCL instance;
private SingtonDCL(){
System.out.println("通过双重校验锁实现单例模式");
}
public static SingtonDCL getInstance(){
if(instance == null){
//使用synchronized同步方法块,可以提升性能
synchronized(SingtonDCL.class){
/**
* 第二次检查的目的是为了防止两个线程都经过了第一道检查
* 然后一个线程抢到锁后进入了代码块,创建了实例,然后释放锁
* 第二个线程又抢到锁进入了代码块
* 如果没有第二次检查,第二个线程就会创建第二个实例
*/
if(instance == null){
instance = new SingtonDCL();
}
}
}
return instance;
}
}