目录

单例模式(Singleton)

最简单的单例类

加锁版单例类

内部类单例类


单例模式(Singleton)

1、单例对象(Singleton)是一种常用的设计模式,在 Java 应用中,单例对象能保证在一个 JVM 中,该对象只有一个实例存在。

2、这样的模式有几个好处:

1)某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。

2)省去了 new 操作符,降低了系统内存的使用频率,减轻 GC 压力。

3)多线程中进行数据共享,有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程。

3、需要清楚的是单例模式作为一种模式,其实现方式并不是规定死的,可以是任意的,只要能达到期望的效果即可。也就是说实际情况中可能大家写的各有不同,但是大同小异。

最简单的单例类

1、下面开始写一个简单的单例类:

import java.util.logging.Logger;
/*** Created by Administrator on 2019/4/8 0008.* trade:交易,实现单例模式*/
public class Trade {//私有静态实例,防止被引用。此处赋值为 null,目的是实现延迟加载private static Trade instance;//私有构造方法,防止被实例化private Trade() {}//静态工程方法,创建实例public static Trade getInstance() {if (instance == null) {instance = new Trade();Logger.getAnonymousLogger().info("创建 Trade 实例..." + Thread.currentThread().getName());}return instance;}
}

4、测试如下:

import main.singleton.Trade;
/*** Created by Administrator on 2019/4/8 0008.*/
public class Test {public static void main(String[] args) {for (int i = 0; i < 10; i++) {new Thread() {@Overridepublic void run() {System.out.println("--------------" + Thread.currentThread().getName());Trade.getInstance();}}.start();}}
}

演示的是 10 个线程同时创建 Trade 实例,结果是只有第一个操作的线程会创建一次对象,后面的不会再创建。

加锁版单例类

1、上面的 Trade 类基本可以满足要求,但是像这样毫无线程安全保护的类,如果把它放入多线程的环境下,仍然有可能会出现问题。首先会想到对 getInstance 方法加 synchronized 关键字。

import java.util.logging.Logger;
/*** Created by Administrator on 2019/4/8 0008.* trade:交易,实现单例模式*/
public class Trade {//私有静态实例,防止被引用。此处赋值为 null,目的是实现延迟加载private static Trade instance;//私有构造方法,防止被实例化private Trade() {}//静态工程方法,创建实例,添加了类锁public synchronized static Trade getInstance() {if (instance == null) {instance = new Trade();Logger.getAnonymousLogger().info("创建 Trade 实例..." + Thread.currentThread().getName());}return instance;}
}

2、上面这样添加 synchronized 关键字后,每次调用 getInstance()方法,都要对对象上锁,事实上只有在第一次创建对象的时候需要加锁,之后就不需要了,所以可以改进如下:

import java.util.logging.Logger;
/*** Created by Administrator on 2019/4/8 0008.* trade:交易,实现单例模式*/
public class Trade {//私有静态实例,防止被引用。此处赋值为 null,目的是实现延迟加载private static Trade instance = null;//私有构造方法,防止被实例化private Trade() {}//静态工程方法,创建实例public static Trade getInstance() {if (instance == null) {/*** 创建实例时添加类锁* 这样当第一次 instance 为 null时,添加类锁,后续不再需要加锁*/synchronized (Trade.class) {if (instance == null) {instance = new Trade();Logger.getAnonymousLogger().info("创建 Trade 实例..." + Thread.currentThread().getName());}}}return instance;}
}

3、因为只需要在创建实例的时候进行同步,所以只要将创建实例和 getInstance() 方法分开,单独为创建实例加 synchronized 关键字也是可以的,如下所示:

import java.util.logging.Logger;
/*** Created by Administrator on 2019/4/8 0008.* trade:交易,实现单例模式*/
public class Trade {//私有静态实例,防止被引用。此处赋值为 null,目的是实现延迟加载private static Trade instance = null;//私有构造方法,防止被实例化private Trade() {}//同步创建实例,添加了类锁private synchronized static void syncInit() {if (instance == null) {instance = new Trade();Logger.getAnonymousLogger().info("创建 Trade 实例..." + Thread.currentThread().getName());}}//静态工程方法,创建实例public static Trade getInstance() {if (instance == null) {syncInit();}return instance;}
}

实现方式并不是唯一的,但都是大同小异,除了使用 synchronized 关键字,比如也可以使用 Lock 接口。

内部类单例类

1、加了 synchronized 关键字,只有在 instance 为 null 时,为其创建对象,同时加锁,性能有一定的提升。但是仍然可能存在问题的。

2、Java 指令中创建对象和赋值操作其实是分开进行的,也就是说 instance = new Trade(); 语句是分两步执行的。而 JVM 并不保证这两个操作的先后顺序,也就是说有可能 JVM 会先为新的 Trade 实例分配空间,然后直接赋值给 instance 成员,然后再去初始化这个 Singleton 实例。这样有可能会出错,以 A、B 两个线程为例:

1)A、B 线程同时进入了第一个 if (instance == null) { 判断 
2)A 首先进入 synchronized ,由于 instance 为 null,所以它执行 instance = new Trade();
3)由于 JVM 内部的优化机制,JVM 先划出了一些分配给 Trade 实例的空白内存,并赋值给 instance 成员(注意此时JVM没有开始初始化这个实例),然后 A 离开了synchronized。
4)B 进入 synchronized ,由于 instance 此时不是null,因此它马上离开了synchronized 并将结果返回给调用该方法的程序。 
5)此时 B 线程打算使用 Trade 实例,却发现它没有被初始化,于是错误发生了。

3、可以使用内部类的方式解决如下:

/*** Created by Administrator on 2019/4/8 0008.* trade:交易,实现单例模式*/
public class Trade {//私有构造方法,防止被实例化private Trade() {}//此处使用一个内部类来维护单例//static 修饰的成员变量随着类的加载而加载,在类加载时进行唯一一次的初始化private static class TradeFactory {private static Trade instance = new Trade();}//静态工程方法,创建实例public static Trade getInstance() {return TradeFactory.instance;}
}

1)单例模式使用内部类来维护单例的实现,JVM 内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的,这样当第一次调用 getInstance 的时候,JVM 能够保证 instance 只被创建一次,并且会保证把赋值给 instance 的内存初始化完毕。

2)该方式也只会在第一次调用的时候使用互斥机制。

Java 设计模式 之 单例模式(Singleton)相关推荐

  1. Java设计模式之单例模式(Singleton Pattern)

    **单例模式:用来创造独一无二的,只能有一个实例的对象设计模式.单例模式确保一个类只有一个实例,并提供一个全局访问点.**相比于全局变量(对对象的静态引用),单例模式可以延迟实例化,而且全局变量不能保 ...

  2. 设计模式之单例模式——Singleton

                        设计模式之单例模式--Singleton 设计意图: 保证类仅有一个实例,并且可以供应用程序全局使用.为了保证这一点,就需要这个类自己创建自己的对象,并且对外有 ...

  3. Java设计模式之单例模式(七种写法)

    Java设计模式之单例模式(七种写法) 第一种,懒汉式,lazy初始化,线程不安全,多线程中无法工作: public class Singleton {private static Singleton ...

  4. Java设计模式之单例模式的学习

    本篇是本人的第二篇博客 旨在记录本人对于Java设计模式之单例模式的学习和理解,也希望本篇可以对一些正在学习的小伙伴起到一些帮助 单例模式(singleton)的特点: 1.单例模式有且仅有一个实例: ...

  5. Java 设计模式之单例模式

    单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 这种模式涉及到一个单一的类,该类负责创建自己的对 ...

  6. Java设计模式(二) -- 单例模式

    单例模式是Java中最广泛应用的设计模式之一,为创建对象提供了一种绝佳的方式.因此,在一些Java程序中, 一些管理器和控制器经常被设计为单例模式. 这种模式涉及到一个单一的类,该类负责创建自己的对象 ...

  7. java设计模式之单例模式(七种方法)

    单例模式:个人认为这个是最简单的一种设计模式,而且也是在我们开发中最常用的一个设计模式. 单例模式的意思就是只有一个实例.单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个 ...

  8. Java 设计模式(3)单例模式

    前言 概念: java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自 ...

  9. java设计模式之——单例模式(八种实现)

    一.介绍 有时,我们需要某个类的实例始终只有一个,举个例子,如果用面向对象语言写的操作系统,那么桌面这个实例肯定就只有一个,无论从哪个地方进入的桌面,都是同一个. 所谓类的单例设计模式,就是采取一定的 ...

  10. 设计模式之——单例模式(Singleton)的常见应用场景(转):

    单例模式(Singleton)也叫单态模式,是设计模式中最为简单的一种模式,甚至有些模式大师都不称其为模式,称其为一种实现技巧,因为设计模式讲究对象之间的关系的抽象,而单例模式只有自己一个对象,也因此 ...

最新文章

  1. 网站推广——网站推广专员建设网站是选择新域名还是老域名?
  2. [设计模式]简单工厂模式
  3. PP面向订单生产模式探讨
  4. 2、mybatis主配置文件之properties
  5. 笔记:《幸福的方法》
  6. 虚拟机安装centos
  7. python和c 的区别-C++/C/JAVA/Python之间的区别?
  8. matlab人工神经网络教程,人工神经网络作业MATLAB仿真(共3篇)
  9. 9.郝斌C语言笔记——变量的作用域和存储方式
  10. 谷歌大牛Jeff Dean亲自撰文:深度学习研究的黄金十年
  11. matlab ramp函数,一文教你快速搞懂 FOC ramp function 斜坡函数的作用和实现
  12. beyong compare激活
  13. Windows Sever 2008 文件夹共享权限
  14. Python爬取雪球7*24小时信息
  15. 程序、任务、进程和线程的联系与区别
  16. 激光SLAM理论与实践(一)--激光SLAM简要介绍
  17. JAVA计算机毕业设计跨境电商网站(附源码、数据库)
  18. TCP端口检测、网络连接时延测试工具 tcping
  19. 64位计算机int类型字长,64位整数问题
  20. 使用springboot访问本地电脑资源,并解决中文路径无法访问的问题

热门文章

  1. jquery中防止和其他JS框架冲突的办法
  2. System.Windows.Forms.TreeView
  3. 直推学习(transductive learning)
  4. java 模式匹配_java模式匹配之蛮力匹配
  5. 【大数据部落】文本挖掘:twitter推特LDA主题情感分析
  6. 一段python算法实战的代码
  7. python list 分批batch
  8. c语言寻找文件指令,c语言实现文件查找
  9. 【C/C++】C++重复率最高、最经典面试题/笔试题【持续更新】
  10. 【C/C++】C++基本语法