单例模式(JAVA实现)

单例模式是为了保证一个类在一个系统中同时只有一个实例存在(可以很好地节约资源,避免频繁创建和销毁对象)。
比如spring中的@Autowired。

实现的基本原理:每次获取对象前,先判断系统中是否已经有这个单例对象,有则返回,没有则创建。单例模式的类构造函数时私有的,不允许类外方法使用new关键字创建对象。

懒汉模式(线程安全)
在类中定义单例对象,但并未实例化,是在获取单例对象的方法中进行实例化的。所以在第一次调用懒汉模式时,该对象一定为空,然后实例化对象并赋值,这样下次就能直接获取对象了。

public class Main {
    public static void main(String[] args) {
        LazySingleton singleton = LazySingleton.getInstance();
        System.out.println(singleton.hashCode());
        LazySingleton singleton1 = LazySingleton.getInstance();
        System.out.println(singleton1.hashCode());
    }
}
class LazySingleton{
    private static LazySingleton instance;
    private LazySingleton(){}
    public static synchronized LazySingleton getInstance(){
        if(instance == null){
            instance = new LazySingleton();
        }
        return instance;
    }

}

运行结果
在这里插入图片描述
饿汉模式
饿汉模式是在定义单例对象的同时进行初始化(在类加载完成时,该类实例已经存在在JVM中)

public class Main {
    public static void main(String[] args) {
        HungrySingleton hungrySingleton1 = HungrySingleton.getInstace();
        System.out.println(hungrySingleton1.hashCode());
        HungrySingleton hungrySingleton2 = HungrySingleton.getInstace();
        System.out.println(hungrySingleton2.hashCode());
    }
}
class HungrySingleton{
    private static HungrySingleton hungrySingleton = new HungrySingleton();
    private HungrySingleton(){}
    public static HungrySingleton getInstace(){
        return hungrySingleton;
    }

}

静态内部类
在类中定义一个静态内部类,将对象实例的定义和初始化放在内部类中完成,在获取对象时要通过静态内部类调用其单例对象。
因为类的静态内部类在JVM中是唯一的,可以很好地保障单例对象的唯一性。

public class Singleton{
	private static class SingletonHolder{
		private static final Singleton INSTANCE = new Singleton();
	}
	private Singleton(){}
	public static final Singleton getInstance(){
		return SingletonHolder.INSTANCE;
	}
}

双重校验锁
在懒汉模式的基础上做进一步优化。
在之前的懒汉式synchronized方法,会导致很大的性能开销,并且加锁只需要在第一次初始化的时候使用,之后的调用没必要加锁了。
所以使用双重校验锁(double checked locking)进行优化。先判断对象是否被初始化,若未初始化,则进行加锁,再判断对象是否初始化,若未初始化,则进行初始化。

  • 使用volatile关键字修饰singleton对象,因为volatile会禁止指令重排,所有写操作都将发生在读操作之前。
    new Object()在底层可以分解成三个步骤:
    1.分配内存空间
    2.初始化对象
    3.将对象指向刚分配的内存空间
    如果对象不使用volatile修饰,假如步骤2.3及进行重排序,那么可能会访问到一个初始化未完成的对象。
    比如:
    在这里插入图片描述
public class Main {
    public static void main(String[] args) {
        DCLSingleton dclSingleton = DCLSingleton.getInstance();
        System.out.println(dclSingleton.hashCode());
        DCLSingleton dclSingleton1 = DCLSingleton.getInstance();
        System.out.println(dclSingleton1.hashCode());
    }
}
class DCLSingleton{
    private volatile static DCLSingleton dclSingleton;
    private DCLSingleton(){}
    public static DCLSingleton getInstance(){
        if(dclSingleton == null){
            synchronized (DCLSingleton.class){
                if(dclSingleton == null){
                    dclSingleton = new DCLSingleton();
                }
            }
        }
        return dclSingleton;
    }
    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值