单例设计模式是一个 确保一个类只有一个实例对象,它保证了全局对象的唯一性。
特点:
- 一个类只有一个实例。
- 一个类自己创建自己的实例。
- 一个类需给其他类提供这一个实例(提供的这个类的方法必须是静态的)。
单例模式分为懒汉式和恶汉式两种。
恶汉式: 在程序启动或单例模式类被加载的时候,单例模式实例就已经被创建。(我的理解是:一上来就创建的是恶汉式)
懒汉式: 当程序第一次访问才会创建单例模式的示例。(我的理解是:使用时才会创建的是懒汉式)
步骤:
- 将该类的构造方法定义为私有方法,这样其他处的代码就无法通过调用该类的构造方法来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例;
- 在该类内提供一个可见的静态方法,当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用。
1. 饿汉式单例模式
/**
* 饿汉式单例模式:一上来就创建实例
*/
public class ESingleton {
// 1. 构造方法私有化,这样其他类创建不了该类的示例对象,保证了全局对象的唯一性
private ESingleton(){}
// 2. 产生一个唯一的对象,通过类名调用,在类加载之前就已经创建好了
private static final ESingleton singleton = new ESingleton();
// 3. 给外部类提供获取该实例的方法
// 因为外部类只能通过对象调用普通方法,但是外部类不能创建对象,所以该方法应设立为静态方法,通过类名调用
public static ESingleton getInstance(){
return singleton;
}
}
测试代码:
public class TestDemo {
public static void main(String[] args) {
// 获得实例
ESingleton singleton1 = ESingleton.getInstance();
ESingleton singleton2 = ESingleton.getInstance();
// == 比较的的两个对象的地址
if(singleton1 == singleton2){
System.out.println("true");
}
else{
System.out.println("false");
}
}
}
运行结果:
2. 懒汉式单例模式
/**
* 懒汉式单例模式:使用时才会创建
*/
public class LSingleton {
// 1. 构造方法私有化
private LSingleton(){}
// 2. 创建引用
private static LSingleton singleton = null;
// 3. 提供外部接口
public static LSingleton getInstance(){
if(singleton == null){
singleton = new LSingleton();
}
return singleton;
}
}
测试代码:
public class TestLSingleton {
public static void main(String[] args) {
LSingleton singleton1 = LSingleton.getInstance();
LSingleton singleton2 = LSingleton.getInstance();
if(singleton1 == singleton2){
System.out.println("true");
}else{
System.out.println("false");
}
}
}
运行结果:
饿汉式单例模式是一上来就创建对象,所以在类加载是就已经创建好了,且只对外部只有获得接口,所以饿汉式单例模式是线程安全的。
懒汉式单例模式是使用时才会创建对象,所以在多线程模式下,当一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。因此在多线程下,会出现线程安全问题,所以有了下面的Double-Check。
3. 懒汉式单例模式:Double-Check
Double-Check概念对于多线程开发者来说不会陌生,我们进行了两次if (singleton==null)检查,这样就可以保证线程安全了。这样,实例化代码只用执行一次,后面再次访问时,判断if (singleton==null),直接return实例化对象。
/**
* 懒汉式单例模式:双重检查
*/
public class LYSingleton {
// 1. 构造方法私有化
private LYSingleton(){}
// 2. 创建引用
private static volitle LYSingleton singleton = null;
// 3. 提供外部接口
public static LYSingleton getInstance(){
if(singleton == null){
synchronized (LYSingleton.class){
if(singleton == null){
singleton = new LYSingleton();
}
}
}
return singleton;
}
}