栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java实现单例模式总结

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java实现单例模式总结

这种

1.单例模式简介

单例模式属于设计模式中的创建型模式。它主要用于一个类只能有一个实例的场景(想想一些只能有一个或者只需要一个的资源的场景),哪怕是多线程在访问这个实例,除此之外,需要提供一个全局访问它的点。

2.单例模式实现的方式

单例模式有很多实现方法,在这里只提供几种常见的,分别是饿汉、懒汉、静态内部类、枚举类

2.1 饿汉
public class HungrySingleton {
    // 饿汉模式,程序启动的时候直接加载 线程安全 线程安全由虚拟机保证
    // 这里使用final关键词是为了防止子类继承破坏单例
    private static final HungrySingleton instance = new HungrySingleton();
    // 构造方法设为私有,防止外部new创建
    private HungrySingleton() {}

    public static HungrySingleton getInstance() {
        return instance;
    }
}

优点:线程安全由虚拟机保证,可靠,外部需要使⽤的时候获取即可。

缺点:

(1)无论程序中是否使用都会在程序启动之初进⾏创建,有可能浪费空间(创建了但不使用)。

(2)这种形式的单例过多可能导致程序启动时间过长。

(3)私有化构造器方法不能防止外部创建会被暴力发射破坏。

2.2 懒汉

顾名思义,只有在真正使用的时候才会加载并创建该单例对象。

对于这种实现方式的单例模式,主要有两种,分别为

public class LazySingleton {
    // 这里使用volatile是为了防止instance = new LazySingleton();发生指令重排
    private static volatile LazySingleton instance;

    private LazySingleton() {};


    public static synchronized LazySingleton LazySingleton() {
        if (null != instance) {
            return instance;
        }
        instance = new LazySingleton();
        return instance;
    }

}

此方法实现主要通过方法锁的形式实现多线程安全,但这种加锁方式过于笨重,多线程在该方法上都是串行化,对于并发量高的常见不建议使用,以下是一种优化后的方案:

public class LazySingleton {
    // 这里使用volatile是为了防止instance = new LazySingleton();发生指令重排
    private static volatile LazySingleton instance;

    public static LazySingleton getInstance() {
        if (null != instance) {
            return instance;
        }

        synchronized (LazySingleton.class) {
            if (null == instance) {
                instance = new LazySingleton();
            }
        }

        return  instance;
    }
}

此方法实现也叫双重校验锁形式的单例,相较于把锁加载方法上,第一重校验单例是否为空就能处理大部分的并发请求,减小了锁的竞争。一定程度上优化了性能。

两个问题:

(1)为什么要双重校验:

有了第一重校验,还要有第二重校验的原因,可以考虑这样一个场景,即两个线程并发访问getInstance方法,且此时还没有创建instance对象,那么两个线程均能通过第一重校验锁,那么到了同步代码块,假设第一个线程先进去创建了单例对象(第二个线程阻塞等待),释放锁,第二个线程进去又一次创建了单例对象(没有第二重校验的话),破坏了单例的特性。

(2)volatile关键词的作用

这里使用volatile关键词的作用主要是为了防止instance = new LazySingleton();语句发生指令重排。这个语句如果发生指令重排,有可能先给instance引用赋值,再调用LazySingleton的构造方法,如果这两个操作之间有别的线程调用getInstance方法,则会返回一个还没有初始化完的LazySingleton对象。

优点:线程安全,懒加载,一定程度上可以节省内存资源。

缺点:加锁的⽅式实现线程安全耗费性能。私有构造器方法防止外部创建会被暴力发射破坏

2.3 枚举
public enum EnumSingleton {
    INSTACE;
}

使用

public class Test {
    public static void main(String[] args) {
        System.out.println(EnumSingleton.INSTACE.toString());
    }
}

优点:线程安全,其线程安全由虚拟机保证,而且可以防止暴力反射破坏单例,总得来说也是一种比较推荐的方式

缺点:饿汉式实现思想。有可能浪费空间,但设计合理可以避免这个问题。

2.4 静态内部类
public class InnerSingleton {

    private InnerSingleton() {}

    private static class InnerClass {
        private static InnerSingleton instance = new InnerSingleton();
    }

    public static InnerSingleton getInstance() {
        return InnerClass.instance;
    }
}

优点:不用加锁实现两线程安全,其线程安全由虚拟机保证,且也实现了懒加载的思想,用的时候再创建,这是一种比较推荐的单例模式实现方式。

缺点:私有化构造器方法不能防止外部创建会被暴力发射破坏。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1036099.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号