1.什么是单例模式
单例模式是指一个单一的类,这个类负责创建自己的对象,且只能有一个对象被创建,这个类还提供了唯一的访问这个类的唯一对象的方式,不能被实例化。(私有构造方法表示外不能new这个对象共有静态方法返回实例对象,调用始终返回一个对象)
2.单例模式的主要的解决的问题
主要用于一个全局使用的类被频繁的创建和销毁,使用单例模式提高代码效率,节省系统资源
3.应用场景
- 要求生产唯一序列号。
- WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
- 创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
4.单例模式的实现方法
- 饿汉模式,线程安全:在内加载的时候直接初始化,如
Singleton instance = new Singleton();
它基于 classloader 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance 方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 显然没有达到 lazy loading 的效果。
实现代码:
public class Singleton{
private Static Singleton INSTANCE = new Singleton();
private Singleton() {}
public Singleton getInstance{return INSTANCE;}
}
- 懒汉模式,线程不安全:在类加载的时候不对类进行初始化,在需要对象的引用的时候才去对类进行初始化,但是也是因为在需要时才初始化,会导致对象初始化很多次,不满足线程安全。
实现代码:
public class Singleton{
private Static Singleton INSTANCE;
private Singleton() {}
public Singleton getInstance{
if(INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;}
}
- 懒汉模式,线程安全:也是在需要引用的时候对对象进行初始化,但是通过加锁,使得其他线程不能在对其进行初始化,满足线程安全,但是多次的加锁,开锁,增加了系统的调用,浪费了资源。
实现代码:
public class Singleton{
private Static Singleton INSTANCE;
private Singleton() {}
public Singleton synchronized getInstance{
if(INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;}
}
- 懒汉模式,双重校验锁:由于普通的懒汉模式加了太多的不需要的锁,双重校验锁的实现就是为了解决加锁过多,浪费资源的问题。这种方法不需要将整个方法都进行加锁,只需要对要进行的实例化的对象进行加锁,其他线程执行到这一样代码会先等之前的锁解除,由于会出现线程B执行到加锁的代码时,线程A正在对其进行操作,且操作结束后会改变金泰变量,导致线程B的获得的静态变量不是想要的结果,所以要用volatile修饰静态变量,使其可视化,并且保证执行时的指令顺序不会发生变化。
实现代码:
public class Singleton{
private volatile Static Singleton INSTANCE;
private Singleton() {}
public Singleton getInstance{
if(INSTANCE == null) {
synchronized(Singleton.class) {
if(INSTANCE == null)
INSTANCE = new Singleton();
}
}
return INSTANCE;}
}