单例模式
实现思路
-
首先,目标是什么?
使某一个类的实例全局唯一,避免重复创建对象,节省内存资源
同时有些对象不应该甚至不能有多个实例
-
那么如何做到?
首先私有化构造方法,这样其他所有类都不能任意创建该对象的实例,除了他自己。所以这个唯一对象会是他自己调用自己的构造方法创建出来的
根据创建时机的不同,又分为“饿汉式”和“懒汉式”
- 饿汉式:在类初始化时就创建好,所以是
private static - 懒汉式:在
getInstance()被调用时创建
而且自己创建的也是静态(类)实例,这样才能保证唯一
- 饿汉式:在类初始化时就创建好,所以是
-
那其他类如何获取这个唯一实例呢?
通过公有暴露的
getInstance()方法,返回这个实例对象注意,为了避免“鸡生蛋,蛋生鸡”的问题,这个
getInstance()方法也是static,可以直接通过类名.getInstance()调用,而不需要实例化对象再调用 -
如果多线程并发
getInstance()会怎么样?饿汉模式没有线程安全问题,只考虑懒汉式代码:
public LazySingleton getInstance(){ if(lazySingleton==null) lazySingleton = new LazySingleton(); return lazySingleton; }当实例还没有被实例化,此时两个线程同时
getInstance(),他俩对于if(instance==null)的判断都是true,然后各自去实例化了一个实例(虽然后面的会覆盖前面的引用地址,但是确实是在堆区实例化了两个对象)或者是一个线程判断完,但是还没完成实例化,另一个线程进来判断了
那么如何解决?
最直接的就是给
getInstance()方法加上synchronized关键字,但是仔细想,除了第一次实例化的时候需要同步,后面的判空和获取实例并不需要同步,同步了反而会降低效率那么…同步代码块?只对
if语句加锁?好像好一些了,但是还不够,因为如果每个线程都要排队判断,好像跟上面同步方法差不多我们需要尽可能排除同步对后面的影响,对
new同步?好像也不行,如果多线程判断已经结束了,那么实例化也只是排队的问题,仍然会创建多个实例所以最后变成了这样,两次空判断
public static Singleton getInstance(){ if(instance==null){ synchronized (Singleton.class){ if(instance==null) instance = new Singleton(); }} return instance; }但是这里还有一点需要考虑,为什么这里加了一个
volatile关键字?private volatile static Singleton instance;我们知道
volatile关键字是用来保证多线程间对变量的可见性书上的说法是:
确保当
uniqueInstance变量被初始化成Singleton实例时,多个线程能正确处理uniqueInstance变量看网上文章说是防止实例化过程中的指令重排
instance = new Singleton(); // 防止被排成1,3,2 // 可以分解为以下三个步骤 1 memory=allocate();// 分配内存 相当于c的malloc 2 ctorInstanc(memory) //初始化对象 3 s=memory //设置s指向刚分配的地址不甚理解,可以参考这篇文章
代码
饿汉模式
/**
* 饿汉式的单例模式
* @author yao 2022/12/8
*/
public class HungrySingleton {
// 饿汉式在类加载时就实例化对象
private static HungrySingleton hungrySingleton=new HungrySingleton();
/**
* 私有化构造方法,只有类本身可以创建实例
*/
private HungrySingleton(){}
/**
* 公开暴露的方法可以让其他类获取到这个唯一实例
* @return 本类的唯一实例
*/
public static HungrySingleton getInstance(){
return hungrySingleton;
}
}
懒汉模式
/**
* 懒汉模式单例
* @author yao 2022/12/8
*/
public class LazySingleton {
// 懒汉模式不在类初始化时实例化对象
private static LazySingleton lazySingleton;
/**
* 这个写出来其实就只是为了加个private
* 当然这么说只是因为构造方法没有参数
*/
private LazySingleton(){}
public LazySingleton getInstance(){
// 只有在被调用的时候才会实例化对象,而且只会被实例化一次
if(lazySingleton==null) lazySingleton = new LazySingleton();
return lazySingleton;
}
}
线程安全写法
/**
* 线程安全且效率最高的实现
* @author yao 2022/10/10
*/
public class Singleton {
private volatile static Singleton instance;
public static Singleton getInstance(){
if(instance==null){
synchronized (Singleton.class){
if(instance==null) instance = new Singleton();
}
}
return instance;
}
}

浙公网安备 33010602011771号