单利模式的应用场景:

  单利模式(Singleton Pattern)是指确保一个类在任何情况下都绝对只有一个实例。并提供一个全局反访问点。单利模式是创建型模式。单利模式在生活中应用也很广泛,比如公司CEO只有一个,部门经理只有一个等。JAVA中ServletCOntext,ServetContextCOnfig等,还有spring中ApplicationContext应用上下文对象,SessionFactory,数据库连接池对象等。使用单利模式可以将其常驻于内存,可以节约更多资源。

写法:

  1:懒汉模式(线程不安全)

/**
* 线程不安全的懒汉式单利模式
*
* Created by gan on 2019/11/17 17:33.
*/
public class LazySingleton {
private static LazySingleton instance; //构造方法私有化
private LazySingleton() {
} public static LazySingleton getInstance() {
if (instance != null) {
instance = new LazySingleton();
}
return instance;
}
}

  上面的代码,提供一个静态对象instance,构造函数私有化防止外部创建对象,提供一个静态的getInstance方法来给访问者一个单利对象。这种写法的缺点就是没有考虑到线程安全问题,当多个访问者同时访问的时候很有可能创建多个对象。之所以叫懒汉式,是因为这种写法是使用的时候才创建,起到了懒加载Lazy loading的作用,实际开发中不建议采用这种写法。

  2:线程安全的懒汉式(加锁)

/**
* 线程安全的懒汉式单利模式
*
* Created by gan on 2019/11/17 17:33.
*/
public class LazySingleton {
private static LazySingleton instance; //构造方法私有化
private LazySingleton() {
} public synchronized static LazySingleton getInstance() {
if (instance != null) {
instance = new LazySingleton();
}
return instance;
}
}

  这种写法就是在第一种的基础上添加了synchronized关键字保证了线程安全。这种写法在并发高的时候虽然保证了线程安全,但是效率很低,高并发的时候所有访问的线程都要排队等待,所以实际开发中也不建议采用。

  3:恶汉式(线程安全)

/**
* 饿汉式(线程安全)
* Created by gan on 2019/10/28 22:52.
*/
public class HungrySigleton { public static final HungrySigleton instance = new HungrySigleton(); private HungrySigleton(){} public static HungrySigleton getInstance(){
return instance;
}
}

  直接在运行(加载)这个类的时候创建了对象,之后直接访问。显然这种方式没有起到Lazy loading的效果。但是是线程安全的,实际开发中还是比较常用。

  4:静态内部类(线程安全)

/**
* 静态内部类方式
* Created by gan on 2019/11/17 17:46.
*/
public class StaticInnerClassSingleton { //构造方法私有化
private StaticInnerClassSingleton() {} //内部类
private static class HolderInnerClass {
//需要提供单利对象的外部类作为静态属性加载的时候就初始化
private static StaticInnerClassSingleton instance = new StaticInnerClassSingleton();
} //对外暴漏访问点
public static StaticInnerClassSingleton getInstance() {
return HolderInnerClass.instance;
}
}

  这种内部类跟饿汉式单利有很多相似的地方,相比饿汉式单利模式的区别也是好处在于:静态内部类不在单利类加载时就加载,而是在调用getInstance()方法的时候才进行加载,达到了类似于懒汉式的效果,而且这种方法又是线程安全的。实际开发中也建议采用。

  5:枚举方法单利(线程安全)

/**
* 枚举单利模式
* Created by gan on 2019/11/17 17:57.
*/
public enum EnumSingleton {
INSTANCE; public void otherMetthod() {
System.out.println("需要单利对象调用的方法。。。");
}
}

  Effective Java作者Josh Bloch提倡的方式,好处有如下:

  1:自由串行化。

  2:保证了一个实例

  3:线程安全

  这种方式防止了单利模式被破坏,而且简洁写法简单,而且绝对的线程安全,但是有个缺点就是不能继承。

  6:双重检查法(通常线程安全,低概率不安全)

/**
* Double check
* Created by gan on 2019/11/17 18:03.
*/
public class DoubleCheckSingleton {
private static DoubleCheckSingleton instance; private DoubleCheckSingleton() {} public static DoubleCheckSingleton getInstance() {
if (instance == null) {
synchronized (DoubleCheckSingleton.class) {
if (instance == null) {
instance = new DoubleCheckSingleton();
}
}
}
return instance;
}
}

  上面的这种写法在并发极高的时候也可能会出现问题(当然这种概率非常小,但是毕竟还是有的嘛),解决的方案就是给instance的声明加上volatile关键字即可。于是就出现了下面第7总写法。

  7:Double check(volatile)

/**
* Double check volatile
* Created by gan on 2019/11/17 18:03.
*/
public class DoubleCheckSingleton {
private volatile static DoubleCheckSingleton instance; private DoubleCheckSingleton() {} public static DoubleCheckSingleton getInstance() {
if (instance == null) {
synchronized (DoubleCheckSingleton.class) {
if (instance == null) {
instance = new DoubleCheckSingleton();
}
}
}
return instance;
}
}

volatile关键字的其中一个作用就是禁止指令重排序,把instance声明volatile后,对它的操作就会有一个内存屏障(什么是内存屏障?),这样在赋值完成之前,就不会调用读操作。这里具体的原因网上也是众说纷纭,这里不进行具体阐述。

  8:ThreadLocal实现单利模式(线程安全)

/**
* ThreadLocal实现单利模式
* Created by gan on 2019/11/17 18:17.
*/
public class ThreadLocalSingleton { private static final ThreadLocal<ThreadLocalSingleton> threadLocal = new ThreadLocal() {
@Override
protected ThreadLocalSingleton initialValue() {
return new ThreadLocalSingleton();
}
}; private ThreadLocalSingleton(){} public static ThreadLocalSingleton getInstance(){
return threadLocal.get();
}
}

  ThreadLocal会为每个线程提供一个独立的变量副本,从而隔离了多个线程堆数据的访问冲突。对于多线程资源共享问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal则采用了“以空间换时间”的方式(主要就是避免了加锁排队)。 前者提供一份变量,让不同的线程排队访问,而后者为每一个线程提供了一份变量,因此可以同时访问而互不影响。但是实际是创建了多个单利对象的。

单利模式的破坏:

  1:序列化破坏

    一个对象创建好以后,有时候需要将对象序列化然后写入磁盘。下次在从磁盘中读取并反序列化,将其转化为内存对象。反序列化后的对象会重新分配内存,即创建型的对象。这样就违背了单利模式的初衷。解决这种方式的方法就是在单利类中新增一个 private Object readResolve();方法即可,具体原因可以看看序列化和反序列化的源码。

  2:反射

    通过反射“暴力破解”也能破坏单利模式,具体暂时不阐述。

  3:克隆

    克隆也会破坏单利模式,具体暂时不阐述。

代码链接:https://gitee.com/ganganbobo/gps-parent

Java设计模式之单利模式(Singleton)的更多相关文章

  1. Java 设计模式之单利模式

    一.首先介绍一下单例模式:     单例模式(Singleton),也叫单子模式,是一种常用的软件设计模式.在应用这个模式时,单例对象的类必须保证只有一个实例存在.许多时候整个系统只需要拥有一个的全局 ...

  2. java 设计模式之单利模式以及代理模式(静态)

    1:单利模式: public class Singleton { private static Singleton uniqueInstance = null; private Singleton() ...

  3. java设计模式3--单例模式(Singleton)

    本文地址:http://www.cnblogs.com/archimedes/p/java-singleton-pattern.html,转载请注明源地址. 单例模式 保证一个类仅有一个实例,并提供一 ...

  4. Java设计模式之工厂模式(Factory模式)介绍(转载)

    原文见:http://www.jb51.net/article/62068.htm 这篇文章主要介绍了Java设计模式之工厂模式(Factory模式)介绍,本文讲解了为何使用工厂模式.工厂方法.抽象工 ...

  5. java设计模式6--适配器模式(Adapter )

    本文地址:http://www.cnblogs.com/archimedes/p/java-adapter-pattern.html,转载请注明源地址. 适配器模式(别名:包装器) 将一个类的接口转换 ...

  6. java设计模式5--原型模式(Prototype)

    本文地址:http://www.cnblogs.com/archimedes/p/java-prototype-pattern.html,转载请注明源地址. 原型模式 用原型实例指定创建对象的种类,并 ...

  7. Java设计模式——装饰者模式

    JAVA 设计模式 装饰者模式 用途 装饰者模式 (Decorator) 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator 模式相比生成子类更为灵活. 装饰者模式是一种结构式模式 ...

  8. 浅析JAVA设计模式之工厂模式(一)

    1 工厂模式简单介绍 工厂模式的定义:简单地说,用来实例化对象,取代new操作. 工厂模式专门负责将大量有共同接口的类实例化.工作模式能够动态决定将哪一个类实例化.不用先知道每次要实例化哪一个类. 工 ...

  9. JAVA设计模式--装饰器模式

    装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰 ...

随机推荐

  1. How to Get What You Want 如何得到你想要的

    [1]If you want something, give it away. [2]When a farmer wants more seeds, he takes his seeds and gi ...

  2. 搭建YUM本地仓库

    本文介绍如何利用CentOS 7 ISO光盘镜像搭建YUM本地仓库. 环境准备: (1)VMware15.5版本虚拟机 (2)CentOS-7-x86_64-DVD-1908光盘镜像文件 1. 搭建Y ...

  3. Qt5教程: (7) 模态/非模态对话框

    模态对话框就是在其没有被关闭之前,用户不能与同一个应用程序的其他窗口进行交互,直到该对话框关闭. 非模态对话框就是在被打开时,用户既可选择和该对话框进行交互,也可以选择同应用程序的其他窗口交互. 1. ...

  4. NoticeBoard

    本人蒟蒻,请轻点虐. 本人是一个即将退役的蒟蒻. 有些题目和模拟赛用密码保护起来了,请小伙伴们不要猜了,猜不出来的.想知道大佬们如果想查看可以直接找我问,您们高抬贵眼会让我受宠若惊. 哇终于有人找我要 ...

  5. SpringBoot项目配置Tomcat和JVM参数

    设置Tomcat端口号和连接数等 使用application.properties配置文件有一些参数无法设置,所以推荐创建一个类文件来配置,如下: package com.qipai.springbe ...

  6. opencv::自定义线性滤波

    卷积概念 常见算子 自定义卷积模糊 卷积概念 1.卷积是图像处理中一个操作,是kernel在图像的每个像素上的操作. 2.Kernel本质上一个固定大小的矩阵数组,其中心点称为锚点(anchor po ...

  7. js转换页面为图片并下载

    <div style="background:red;width: 600px;height: 600px;" class="test"> < ...

  8. python模块-time、datetime

    简单示例: 常用函数封装: # -*- coding: utf-8 -*- # @Time : 2019/8/6 14:37 # @Author : wangmengmeng import datet ...

  9. 入门了解Service Mesh + Istio?从本文开始

    下周六,深圳,阔别已久的线下技术沙龙要和你见面啦! 现场有Rancher Labs研发经理demo刚刚发布的Rancher 2.3中的Istio.Windows容器.集群模板等功能及使用,还有k3s首 ...

  10. mp-vue拖拽组件的实现

    作为一个效率还不错的小前端,自己的任务做完之后真的好闲啊,千盼万盼终于盼来了业务的新需求,他要我多加一个排序题,然后用户通过拖拽来排序,项目经理看我是个实习生,说有点复杂做不出来就算了,我这么闲的一个 ...