什么是单例?
确保一个类只有一个实例,并提供一个全局访问点。
应用
线程池,缓存,数据库等,这些类只需要一个实例,如果多个实例会造成异常的情况。
实现
懒汉式简单的实现
public class Singleton {
private static Singleton singleton;
private Singleton() {
}
public static Singleton getInstance() {
if (singleton == null) {//位置一
singleton = new Singleton();
}
return singleton;
}
}
简单的实现在遇到多线程的时候就会出现问题。比如第一次创建singleton时,线程1执行位置一,这个时候线程2也要获取一个singeton,它也执行到了位置一,然后线程1向下执行获取到了singleton,然后线程2向下执行,singleton又重新被实例化,线程2又获取到一个新的Singeton的实例。
- 应对多线程,那就用synchronized方法吧,重新写getInstance方法
public static synchronized Singleton getInstance(){
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
使用synchronized方法修饰之后,避免了多线程的问题,那我们看看有没有其他的问题?
synchronized 会降低性能,每次获取实例的时候多要判断getInstance方法有没有执行完,但是我们只需要在第一次实例化singleton时需要synchronized。
- 双重检查加锁,在getInstance中减少synchronized,提高性能
private volatile static Singleton singleton4;//volatile关键字确保:当singleton变量被实例化成Singleton实例时,多个线程正确地处理singleton变量
public static Singleton getInstance(){
if (singleton == null) {//检查实例,如果不存在,进去同步区
synchronized (Singleton.class) {//只有第一次才彻底执行这里的代码
if (singleton == null) {//再次判空,
singleton = new Singleton();
}
}
}
return singleton;
}
以上都是懒汉式的单例,也就是延迟加载,用到Singeton实例的时候才创建一个实例。下面看看饿汉式的单例模式
private static Singleton singleton3 = new Singleton();
public static Singleton getInstance(){
return singleton;
}
还有一种内部类的实现方式,比较常用
private static class SingletonHolder{
private static Singleton instance = new Singleton();
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
结束语
- 单例模式确保程序中一个类最多只有一个实例。
- 单例模式提供一个全局访问点。
- 私有的构造器,一个静态方法和一个静态变量。