博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
23种设计模式之单例模式
阅读量:5764 次
发布时间:2019-06-18

本文共 5509 字,大约阅读时间需要 18 分钟。

hot3.png

概念

单例模式是设计模式中使用最为普遍的模式之一。它是一种对象创建模式,用于产生一个对象的具体实例,它可以确保系统中一个类只产生一个实例。

在Java语言中,这样的行为能带来两大好处。

1. 对于频繁使用的对象,可以省略创建对象所花费的时间,这对于一些重量级的对象而言,是非常可观的一笔系统开销。
2. 由于new操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻GC压力,缩短GC停顿时间。

角色

单例模式的参与者非常简单,只有单例类和使用者两个。

1. 单例类,提供单例的工程,返回单例类。
2. 使用者,获取并使用单例类。

基本结构

单例模式的核心在于通过一个接口返回唯一的对象实例。

这里写图片描述

饿汉模式

饿汉模式的单例,在JVM加载单例类时,单例对象就会被建立。如果此时,这个单例类在系统中还扮演者其他角色,那么在任何使用这个单例类的地方都会初始化这个单例变量,而不管是否会被用到。

//饿汉模式public class HungrySingleton {
//利用静态变量来记录singleton的唯一实例 private final static HungrySingleton uniqueInstance=new HungrySingleton(); /** * 构造器私有化,只有singleton内部才可以调用 * 确保不会被其他代码实例化 */ private HungrySingleton(){ System.out.println("HungrySingleton is create"); } public static HungrySingleton getInstance(){ return uniqueInstance; } //其他角色 public static void createString(){ System.out.println("createString in HungrySingleton"); } public static void main(String[] args) { HungrySingleton.createString(); }}

运行结果:

HungrySingleton is create
createString in HungrySingleton

懒汉模式

懒汉模式,实现延迟加载,确保系统启动时没有额外的负载,提高系统在相关函数调用时的反应速度。

线程不安全的懒汉

//线程不安全的懒汉模式public class NoSafeSingleton {
//利用静态变量来记录singleton的唯一实例 private static NoSafeSingleton uniqueInstance; /** * 构造器私有化,只有singleton内部才可以调用 * 确保不会被其他代码实例化 */ private NoSafeSingleton(){ } //线程不安全 //第一个线程进来判断 uniqueInstance == null,还没有new 出实例的时候 。 // 这个时候第二个线程也进来了,判断的uniqueInstance 也是 null,然后也会 new 出实例的 public static NoSafeSingleton getInstance(){ if (null==uniqueInstance){ uniqueInstance=new NoSafeSingleton(); } return uniqueInstance; }}

线程安全的懒汉

为了使用延迟加载引入的同步关键字反而降低了系统性能。

//线程安全的懒汉模式-实现延迟加载public class SyncLazySingleton {    private SyncLazySingleton() {        System.out.println("SyncLazySingleton is create");    }    //instance初始值赋予null,确保系统启动时没有额外的负载    private static SyncLazySingleton instance = null;    //使用同步关键字,防止多个实例被创建(多线程环境),synchronized保证线程安全    public static synchronized SyncLazySingleton getInstance() {        if (instance == null) {            instance = new SyncLazySingleton();        }        return instance;    }    //synchronized保证线程安全,降低了系统性能    public static void main(String[] args) {        new Thread(){            public void run(){                long bg = System.currentTimeMillis();                for (int i = 0; i < 1000000; i++) {// HungrySingleton.getInstance();                     SyncLazySingleton.getInstance();                }                System.out.println("spend:" + (System.currentTimeMillis() - bg)+"ms");            }        }.start();    }}

HungrySingleton is create

spend:5ms

SyncLazySingleton is create

spend:22ms

内部类实现单例

使用内部类的方式实现单例,既可以做到延迟加载,也不必使用同步关键字,是一种比较完善的实现。

//安全的懒汉模式-使用内部类实现单例 ,实现延迟加载public class StaticSingleton {    private StaticSingleton(){        System.out.println("StaticSingleton is create");    }    //JVM加载 StaticSingleton时不会初始化内部类SingletonHolder    //当方法getInstance()被调用时,才会加载getInstance()    private static class SingletonHolder{        private static StaticSingleton instance=new StaticSingleton();    }    public static StaticSingleton getInstance(){        return SingletonHolder.instance;    }    public static void main(String[] args) {        StaticSingleton instance=StaticSingleton.getInstance();        System.out.println(instance);    }}

单例序列化

//序列化和反序列化可能会破坏单例public class SerSingleton implements Serializable {
//私有构造器阻止被实例化 private SerSingleton() { } private static class SingletonHolder {
private static final SerSingleton instance = new SerSingleton(); } public static SerSingleton getInstance() { return SingletonHolder.instance; } //序列化和反序列化可能会破坏单例 //readResolve method to preserve singleton property //阻止生成新的实例,总是返回当前对象 private Object readResolve(){ //Return the true one SerSingleton and let garbage collector // take care of the SerSingleton impersonator. return SingletonHolder.instance; }}

最简洁的单例

//最简洁的单例模式//无偿地提供了序列化机制,绝对防止多次实例化public enum SingletonEnum {    INSTANCE;    public static void main(String[] args) {        SingletonEnum singletonEnum = SingletonEnum.INSTANCE;        SingletonEnum singletonEnum1 = SingletonEnum.INSTANCE;        System.out.println(singletonEnum == singletonEnum1);        System.out.println(singletonEnum.getClass());    }}

true

class org.wuxinshui.boosters.designPatterns.singleton.SingletonEnu

破坏单例

通过反射机制,强行调用单例类的构造函数,生成多个单例,破坏单例模式。

StaticSingleton中添加计数器。

public static final AtomicInteger counter=new AtomicInteger();    private StaticSingleton(){        counter.incrementAndGet();        System.out.println("The "+(counter.get())+" StaticSingleton instance is created");    }
//利用反射破坏单例模式public class ReflectSingleton {    public static void main(String[] args) throws Exception {        StaticSingleton singleton = StaticSingleton.getInstance();        Constructor constructor=singleton.getClass().getDeclaredConstructor();        //值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。        // 值为 false 则指示反射的对象应该实施 Java 语言访问检查。        constructor.setAccessible(true);        StaticSingleton singleton2= (StaticSingleton) constructor.newInstance();        StaticSingleton singleton3= (StaticSingleton) constructor.newInstance();        System.out.println("singleton2==singleton3 :"+(singleton2==singleton3));    }}

运行结果:

The 1 StaticSingleton instance is createdThe 2 StaticSingleton instance is createdThe 3 StaticSingleton instance is createdsingleton2==singleton3 :false

转载于:https://my.oschina.net/wuxinshui/blog/847566

你可能感兴趣的文章
Git原理与高级使用(3)
查看>>
从JDK源码看Writer
查看>>
Express 结合 Webpack 实现HMRwi
查看>>
基于protobuf的RPC实现
查看>>
我的友情链接
查看>>
HAProxy负载均衡原理及企业级实例部署haproxy集群
查看>>
开源中国动弹客户端实践(三)
查看>>
Win 8创造颠覆性体验:预览版关键更新
查看>>
vim在多文件中复制粘贴内容
查看>>
Android ContentObserver
查看>>
疯狂java学习笔记1002---非静态内部类
查看>>
ISA2006实战系列之一:实战ISA三种客户端部署方案(上)
查看>>
TCP服务器
查看>>
AC旁挂三层交换机管理ap,二层接入ap心得
查看>>
JS中比较数字大小
查看>>
jQuery插件的开发
查看>>
基础,基础,还是基础之JAVA基础
查看>>
如何成为一个C++高级程序员
查看>>
ant android 打包签名和渠道
查看>>
我的友情链接
查看>>