内容简介:单例模式为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。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 设计模式——订阅模式(观察者模式)
- 设计模式-简单工厂、工厂方法模式、抽象工厂模式
- java23种设计模式-门面模式(外观模式)
- 简单工厂模式、工厂模式、抽象工厂模式的解析-iOS
- Java 设计模式之工厂方法模式与抽象工厂模式
- JAVA设计模式之模板方法模式和建造者模式
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
首席产品官1 从新手到行家
车马 / 机械工业出版社 / 2018-9-25 / 79
《首席产品官》共2册,旨在为产品新人成长为产品行家,产品白领成长为产品金领,最后成长为首席产品官(CPO)提供产品认知、能力体系、成长方法三个维度的全方位指导。 作者在互联网领域从业近20年,是中国早期的互联网产品经理,曾是周鸿祎旗下“3721”的产品经理,担任CPO和CEO多年。作者将自己多年来的产品经验体系化,锤炼出了“产品人的能力杠铃模型”(简称“杠铃模型”),简洁、直观、兼容性好、实......一起来看看 《首席产品官1 从新手到行家》 这本书的介绍吧!