在Java开发过程中,很多场景下都会碰到或要用到单例模式,在设计模式里也是经常作为指导学习的热门模式之一,相信每位开发同事都用到过。我们总是沿着前辈的足迹去做设定好的思路,往往没去探究为何这么做,所以这篇文章对单例模式做了详解。

一、单例模式定义:

单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。总之,选择单例模式就是为了避免不一致状态,避免政出多头。

二、单例模式特点:

1、单例类只能有一个实例。

2、单例类必须自己创建自己的唯一实例。

3、单例类必须给所有其他对象提供这一实例。

单例模式保证了全局对象的唯一性,比如系统启动读取配置文件就需要单例保证配置的一致性。

三、线程安全的问题

一方面在获取单例的时候,要保证不能产生多个实例对象,后面会详细讲到五种实现方式;

另一方面,在使用单例对象的时候,要注意单例对象内的实例变量是会被多线程共享的,推荐使用无状态的对象,不会因为多个线程的交替调度而破坏自身状态导致线程安全问题,比如我们常用的VO,DTO等(局部变量是在用户栈中的,而且用户栈本身就是线程私有的内存区域,所以不存在线程安全问题)。

四、单例模式的选择

还记得我们最早使用的MVC框架Struts1中的action就是单例模式的,而到了Struts2就使用了多例。在Struts1里,当有多个请求访问,每个都会分配一个新线程,在这些线程,操作的都是同一个action对象,每个用户的数据都是不同的,而action却只有一个。到了Struts2, action对象为每一个请求产生一个实例,并不会带来线程安全问题(实际上servlet容器给每个请求产生许多可丢弃的对象,但是并没有影响到性能和垃圾回收问题,有时间会做下研究)。

五、实现单例模式的方式

1.饿汉式单例(立即加载方式)

//饿汉式单例

public classSingleton1 {//私有构造

privateSingleton1() {}private static Singleton1 single = newSingleton1();//静态工厂方法

public staticSingleton1 getInstance() {returnsingle;

}

}

饿汉式单例在类加载初始化时就创建好一个静态的对象供外部使用,除非系统重启,这个对象不会改变,所以本身就是线程安全的。

Singleton通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance()方法访问。(事实上,通过Java反射机制是能够实例化构造方法为private的类的,那基本上会使所有的Java单例实现失效。此问题在此处不做讨论,姑且闭着眼就认为反射机制不存在。)

2.懒汉式单例(延迟加载方式)

//懒汉式单例

public classSingleton2 {//私有构造

privateSingleton2() {}private static Singleton2 single = null;public staticSingleton2 getInstance() {if(single == null){

single= newSingleton2();

}returnsingle;

}

}

该示例虽然用延迟加载方式实现了懒汉式单例,但在多线程环境下会产生多个single对象,如何改造请看以下方式:

使用synchronized同步锁

public classSingleton3 {//私有构造

privateSingleton3() {}private static Singleton3 single = null;public staticSingleton3 getInstance() {//等同于 synchronized public static Singleton3 getInstance()

synchronized(Singleton3.class){//注意:里面的判断是一定要加的,否则出现线程安全问题

if(single == null){

single= newSingleton3();

}

}returnsingle;

}

}

在方法上加synchronized同步锁或是用同步代码块对类加同步锁,此种方式虽然解决了多个实例对象问题,但是该方式运行效率却很低下,下一个线程想要获取对象,就必须等待上一个线程释放锁之后,才可以继续运行。

public classSingleton4 {//私有构造

privateSingleton4() {}private static Singleton4 single = null;//双重检查

public staticSingleton4 getInstance() {if (single == null) {synchronized (Singleton4.class) {if (single == null) {

single= newSingleton4();

}

}

}returnsingle;

}

}

使用双重检查进一步做了优化,可以避免整个方法被锁,只对需要锁的代码部分加锁,可以提高执行效率。

3.静态内部类实现

public classSingleton6 {//私有构造

privateSingleton6() {}//静态内部类

private static classInnerObject{private static Singleton6 single = newSingleton6();

}public staticSingleton6 getInstance() {returnInnerObject.single;

}

}

静态内部类虽然保证了单例在多线程并发下的线程安全性,但是在遇到序列化对象时,默认的方式运行得到的结果就是多例的。这种情况不多做说明了,使用时请注意。

4.static静态代码块实现

public classSingleton6 {//私有构造

privateSingleton6() {}private static Singleton6 single = null;//静态代码块

static{

single= newSingleton6();

}public staticSingleton6 getInstance() {returnsingle;

}

}

5.内部枚举类实现

public classSingletonFactory {//内部枚举类

private enumEnmuSingleton{

Singleton;privateSingleton8 singleton;//枚举类的构造方法在类加载是被实例化

privateEnmuSingleton(){

singleton= newSingleton8();

}publicSingleton8 getInstance(){returnsingleton;

}

}public staticSingleton8 getInstance() {returnEnmuSingleton.Singleton.getInstance();

}

}classSingleton8{publicSingleton8(){}

}

以上就是本文要介绍的所有单例模式的理解和实现,相信这篇文章能让大家更清楚的理解单例模式,希望大家有问题可以探讨,多多指教!

备注:本文单例实现部分,实例源码参照《Java多线程编程核心技术》-(高洪岩)一书中第六章的学习案例撰写。

java单例设计模式_Java设计模式之单例模式详解相关推荐

  1. java+单例+恶汉_Java设计模式之单例模式(恶汉式和懒汉式)

    /** 单例模式:* 饿汉式:类一加载就创建对象* 懒汉式:用的时候,才去创建对象* 面试题:单例模式的思想是什么?写一个代码体现(我们最好写懒汉式的单例模式给面 /* * 单例模式: *       ...

  2. java单例代码_java中的单例模式的代码怎么写

    单例模式在我们日常的项目中十分常见,当我们在项目中需要一个这样的一个对象,这个对象在内存中只能有一个实例,这时我们就需要用到单例. 一般说来,单例模式通常有以下几种: 1.饥汉式单例 public c ...

  3. java 单例 性能_java程序性能优化之设计优化---单例pk

    对于单例,很多人就要问了.为什么要使用单例,单例意义何在? 单例的产生是由于类的频繁使用,每次生成对象都要new,使用完值后GC要释放对象.这样一来系统性能降低,GC承受着巨大的压力.为了能够提升系统 ...

  4. java单例枚举_Java增强枚举的用例

    java单例枚举 Brian Goetz在消息" 增强枚举-用例 "中写道:"我们希望就现在实现的功能[ 增强枚举 ]获得用户反馈." 他陈述了他的消息的第一个 ...

  5. java 单例设计_Java 之单例设计模式

    设计模式: 对问题行之有效的解决方式, 其实它是一种思想. 单例设计模式 解决的问题:就是可以保证一个类在内存中的对象唯一性. 即单个实例. 比如对于A 和 B 两个程序使用同一个配置信息对象时, A ...

  6. java单例方法_Java单例模式

    单例模式,是特别常见的一种设计模式,因此我们有必要对它的概念和几种常见的写法非常了解,而且这也是面试中常问的知识点. 所谓单例模式,就是所有的请求都用一个对象来处理,如我们常用的Spring默认就是单 ...

  7. java 单例写法_java 单例模式的几种写法

    一.懒汉式 public classSingleton{private static Singleton instance = null;privateSingleton(){}public stat ...

  8. java 单例 实现_java 实现单例的各种方式

    概述 上一篇日志中,我们介绍了单例模式的概念和基础的应用 本节中,我们就来介绍一下 java 语言中如何编写单例模式类 只适合单线程环境的单例模式 public class Singleton { p ...

  9. java 单例类_Java单例类

    单例类: 主要知识点: 1,单例类概念.特点 2,三种单例类懒汉,饿汉,双重加锁举例, 3,懒汉.饿汉区别以及单例类的总结: 1,概念:java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单 ...

  10. 跟着别人学设计模式-----(一)单例模式详解

    作者:zuoxiaolong8810(左潇龙),转载自:http://www.cnblogs.com/zuoxiaolong/p/pattern2.html 上一章,我们学习了设计模式的概念,以及为什 ...

最新文章

  1. PostgreSQL 并行vacuum patch - 暨为什么需要并行vacuum或分区表
  2. 根据遍历序列画二叉树
  3. 符号链接文件_Windows10下创建符号链接(SymbolicLink)
  4. 产品经理经验谈100篇(八)-产品经理分析框架解析
  5. leetcode1302. 层数最深叶子节点的和(深度优先搜索)
  6. 深度学习02——Softmax、DNN、WideDeep Model
  7. 基于redis的分布式锁
  8. 小程序开发(7)-之获取手机号、用户信息
  9. select元素javascript常用操作(转载)
  10. linux ora 00911,python – DatabaseError:ORA-00911:无效字符
  11. SpringMVC系列(四)使用 POJO 对象绑定请求参数值
  12. ImageJ-计算创面面积 此博文包含图片 (2014-01-28 15:59:14)
  13. 构建工具Bazel入门
  14. Science Word安装教程附下载链接
  15. JRebel:Cannot reactivate, offline seat in use.
  16. 任意一个c语言程序实例,C语言程序实例大全下载-C语言程序设计实例大全 - 河东下载站...
  17. php7中shal(),十个你需要在 PHP 7 中避免的坑
  18. ICTCLAS汉语词性标注集+中文字体对应的文件名+ 常用字体、颜色、线性、标记
  19. 计算机在无法打开情况下怎么重置,电脑提示internet explorer无法打开internet站点怎么办...
  20. 彻底解决NSEC病毒

热门文章

  1. 了解JVM运行时的内存分配
  2. java集合数组,数组小到大排序,数组大到小排序
  3. Python __call__()方法
  4. 31 | 深度和广度优先搜索:如何找出社交网络中的三度好友关系?
  5. (一)卷积网络之基础要点
  6. 1015 德才论 (25分)
  7. (二)ElasticSearch6.1.1 Python API
  8. mysql 之jdbc idea版
  9. (JAVA)Integer类之基本数据类型之间的转换
  10. 【C语言进阶深度学习记录】十 C语言中:struct的柔性数组和union分析