单例模式

栏目: 后端 · 发布时间: 7年前

内容简介:单例模式为GOF设计模式中的一种,当我们创建的对象需要昂贵的资源,且该对象又被频繁使用,同时,这个对象的状态是共享的,为了避免资源的浪费以及加载资源的时间,我们往往会引入单例模式。因此,要实现单例模式,其核心就是要在Java语言中,通常提供了如下几种单例模式的实现方式。通过提供一个静态的对象

Preface

单例模式为GOF设计模式中的一种,当我们创建的对象需要昂贵的资源,且该对象又被频繁使用,同时,这个对象的状态是共享的,为了避免资源的浪费以及加载资源的时间,我们往往会引入单例模式。因此,要实现单例模式,其核心就是要 在已有该类的实例前提下,阻止其他开发人员再创建类的新实例

Java 语言中,通常提供了如下几种单例模式的实现方式。

懒汉模式

public class SingletonDemo {
    private static SingletonDemo instance;

    private SingletonDemo() {
    }

    public static SingletonDemo getInstance() {
        if (instance == null) {
            instance = new SingletonDemo();
        }
        return instance;
    }
}

通过提供一个静态的对象 instance ,利用 private 权限的构造方法和 getInstance() 方法来给予访问者一个单例。缺点是,没有考虑到线程安全,可能存在多个访问者同时访问,并同时构造了多个对象的问题。之所以叫做懒汉模式,主要是因为此种方法可以非常明显的 lazy loading 。针对懒汉模式 线程不安全 的问题,我们自然想到了,在 getInstance() 方法前加锁,于是就有了第二种实现。

线程安全的懒汉模式

public class SingletonDemo {
    private static SingletonDemo instance;

    private SingletonDemo() {
    }

    public static synchronized SingletonDemo getInstance() {
        if (instance == null) {
            instance = new SingletonDemo();
        }
        return instance;
    }
}

然而并发其实是一种特殊情况,大多时候这个锁占用的额外资源都浪费了,这种打补丁方式写出来的结构效率很低。

饿汉模式

public class SingletonDemo {
    private static SingletonDemo instance = new SingletonDemo();

    private SingletonDemo() {
        System.out.println("Singleton has loaded");
    }

    public static SingletonDemo getInstance() {
        return instance;
    }
    
    public static void printHello() {
        System.out.println("hello");
    }
}

由于 instance 成员变量使用 static 修饰,在 JVM 首次加载该类时单例对象 instance 会被创建并 常驻内存 ,所以是线程安全的。但显然,这种方法没有起到 lazy loading 的效果。举个例子,也许你只想调用 SingletonDemo.printHello() 方法,但同时打印了 ”Singleton has loaded“,这可能是你不想见到的。

所以我们引入静态类内部加载的方式,也算是单例模式较为完善的解决方案。

静态类内部加载

public class SingletonDemo {
    private SingletonDemo() {
    }

    public static SingletonDemo getInstance() {
        return SingletonHolder.instance;
    }

    private static class SingletonHolder {
        private static SingletonDemo instance = new SingletonDemo();
    }
}

使用 私有内部类 的好处是,静态内部类不会在单例加载时就加载,而是在调用 getInstance() 方法时才进行加载。且单例的创建是在 SingletonHolder 被 JVM 加载时完成,故而也是线程安全的。因此该方法兼备了以上两种实现的优点。

双重校验锁法

public class SingletonDemo {
    private volatile static SingletonDemo instance;

    private SingletonDemo() {
        System.out.println("Singletonhasloaded");
    }

    public static SingletonDemo getInstance() {
        if (instance == null) {
            synchronized (SingletonDemo.class) {
                if (instance == null) {
                    instance = new SingletonDemo();
                }
            }
        }
        return instance;
    }
}

接下来我解释一下在并发时,双重校验锁法会有怎样的情景:

getInstance()
getInstance()

理论上双重校验锁法是线程安全的,并且,这种方法实现了lazy loading。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Text Processing in Python

Text Processing in Python

David Mertz / Addison-Wesley Professional / 2003-6-12 / USD 54.99

Text Processing in Python describes techniques for manipulation of text using the Python programming language. At the broadest level, text processing is simply taking textual information and doing som......一起来看看 《Text Processing in Python》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具