单例模式是一种常用的设计模式,单例模式的定义是单例的类只允许一个实例存在。
单例的实现主要是通过以下两个步骤:
1.将该类的构造方法定义为私有,这样其他类的代码就无法通过调用该类的构造方法来实例化该类的对象,只能通过该类提供的静态方法来获取该类的实例化对象。
2.在类中定义一个静态方法,当调用该静态方法的时候判断该类持有的对象是否为空,如果不为空则返回其引用,如果
类持有的引用为空则创建一个该类的实例并且将其引用赋予该类的保持的引用。
1.饿汉式(静态常量和静态代码块)
//静态常量
public class Singleton {
private final static Singleton INSTANCE = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return INSTANCE;
}
}
//静态代码块
public class Singleton {
private static Singleton instance;
static {
instance = new Singleton();
}
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
优点:在类加载的时候完成了实例化,避免了线程安全的问题。
缺点:类加载的时候完成实例化,没有达到Lazy Loading的效果,如果该实例没有被使用,可能会造成内存资源的浪费。
2.懒汉式(非线程安全和线程安全)
非线程安全,只能用于单线程的环境下,如果在线程1判断后失去CPU时间片,线程2获得CPU时间片进行判断,此时的引用判断为空,线程2创建了一个实例,此时线程1获得CPU时间片,则线程1又创建一个实例,此时无法实现单例。
//非线程安全
public class Singleton {
private static Singleton singleton;
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
线程安全(效率较低)
//线程安全,但是对方法使用synchronized效率较低
public class Singleton {
private static Singleton singleton;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
3.双重检查锁
public class Singleton {
private static volatile Singleton singleton;
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) { //1
if (singleton == null) { //2
singleton = new Singleton(); //3
}
}
}
return singleton;
}
}
在双重检查锁中第二次在synchronized代码块中对singleton进行非空检查是为了解决类似于懒汉模式下非线程安全的问题,保证在多线程的情况下可以实现单例。