Java实现单例模式的五种方法介绍
作者:Knight_AL 时间:2022-10-20 17:32:56
饿汉式
立即加载
防止new对象,构造私有,写一个公共的方法返回对象
占用空间,线程安全
public class Singleton {
/**
* 私有构造
*/
private Singleton(){
System.out.println("构造函数Singleton");
}
private static Singleton singleton = new Singleton();
public static Singleton getInstance(){
return singleton;
}
}
懒汉式
延迟加载
占用空间小,效率有问题,线程不安全
public class Singleton {
/**
* 私有构造
*/
private Singleton(){
System.out.println("构造函数Singleton");
}
private static Singleton singleton = null;
public static Singleton getInstance(){
if (singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
解决线程安全问题
在方法上加synchronized同步锁或是用同步代码块对类加同步锁,此种方式虽然解决了多个实例对象问题,但是该方式运行效率却很低下,下一个线程想要获取对象,就必须等待上一个线程释放锁之后,才可以继续运行。
锁太大
public class Singleton {
/**
* 私有构造
*/
private Singleton(){
System.out.println("构造函数Singleton");
}
private static Singleton singleton = null;
public static synchronized Singleton getInstance(){
if (singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
双重检查锁
提高同步锁的效率
使用双重检查锁进一步做了优化,可以避免整个方法被锁,只对需要锁的代码部分加锁,可以提高执行效率。
第一个if判断
第一个线程进来new了Singleton,那么singleton就有值,第二个线程进来,那么进行第一个if判断,不为null,直接返回,不用再去new了,提升了效率
第二个if判断
两个线程同时进来,在synchronized,第一个线程进入,另一个线程等待,第一个线程new Singleton,然后返回,另一个线程发现了第一个线程走了,进入synchronized,如果不进行if判断,那么还会new Singleton,导致线程不安全
public class Singleton {
/**
* 私有构造
*/
private Singleton(){
System.out.println("构造函数Singleton");
}
private static Singleton singleton = null;
public static synchronized Singleton getInstance(){
if (singleton == null){ //这个检查是提高效率的
synchronized (Singleton.class){
if (singleton == null){
singleton = new Singleton(); //这个检查是防止线程安全的
}
}
}
return singleton;
}
}
静态内部类
这种方式引入了一个内部静态类(static class),静态内部类只有在调用时才会加载,它保证了Singleton 实例的延迟初始化,又保证了实例的唯一性。它把singleton 的实例化操作放到一个静态内部类中,在第一次调用getInstance() 方法时,JVM才会去加载InnerObject类,同时初始化singleton 实例,所以能让getInstance() 方法线程安全。
特点是:即能延迟加载,也能保证线程安全。
静态内部类虽然保证了单例在多线程并发下的线程安全性,但是在遇到序列化对象时,默认的方式运行得到的结果就是多例的。
public class Singleton {
/**
* 私有构造
*/
private Singleton(){
}
private static class InnerObject{
private static Singleton singleton = new Singleton();
}
public static synchronized Singleton getInstance(){
return InnerObject.singleton;
}
}
内部枚举类实现
防止反射和反序列化攻击
实上,通过Java反射机制是能够实例化构造方法为private的类的。这也就是我们现在需要引入的枚举单例模式。
public class SingletonFactory {
/**
* 私有构造
*/
private enum EnumSingleton{
SINGLETON;
private Singleton6 singleton;
//枚举类的构造方法在类加载是被实例化
private EnumSingleton(){
singleton = new Singleton6();
}
public Singleton6 getInstance(){
return singleton;
}
}
public static Singleton6 getInstance(){
return EnumSingleton.SINGLETON.getInstance();
}
}
class Singleton6{
public Singleton6(){
}
}
来源:https://donglin.blog.csdn.net/article/details/128773676