java单例设计模式_Java设计模式之单例模式详解

在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多线程编程核心技术》-(高洪岩)一书中第六章的学习案例撰写。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/430605.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java 压缩文件夹_java 实现压缩文件(单文件 或 文件夹)

接着上篇了解一下java压缩实现过程,下面的是支持 单文件 或 文件夹 压缩的实现,使用递归。效果:代码:package com.gx.compress;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.File;imp…

学习笔记day5:inline inline-block block区别

1. block元素可以包含block元素和inline元素;但inline元素只能包含inline元素。要注意的是这个是个大概的说法,每个特定的元素能包含的元素也是特定的,所以具体到个别元素上,这条规律是不适用的。比如 P 元素,只能包含…

java处理中文字符串_Java实现读取文章中重复出现的中文字符串

在上个星期阿里巴巴一面的时候,最后面试官问我如何把一篇文章中重复出现的词或者句子找出来,当时太紧张,答的不是很好。今天有时间再来亲手实现一遍。其实说白了也就是字符串的处理,所以难度并不是很大。以下是代码和运行效果&…

python的collection系列-默认字典(defaultdict)

默认字典,能定义默认值为其他类型 1 #dic1 {}2 #dic1["k1"].append("kkkkk") #正常情况会报错3 #print(dic1)4 5 import collections6 dic collections.defaultdict(list) #指定字典的值为列表7 dic["k1"].append("…

jquery获取java对象的属性_jQuery - 获得内容和属性

jQuery - 获得内容和属性jQuery 拥有可操作 HTML 元素和属性的强大方法。jQuery DOM 操作jQuery 中非常重要的部分,就是操作 DOM 的能力。jQuery 提供一系列与 DOM 相关的方法,这使访问和操作元素和属性变得很容易。提示:DOM Document Objec…

用border画三角形

<html> <head> <title>用border画三角形</title> <style>#one{width:0px;height:0px;margin:0 auto;border-top:50px solid white;border-right:50px solid white;border-bottom:50px solid orange;border-left:50px solid white;} </style&g…

iOS9适配(包括APNs)的改变

https://github.com/ChenYilong/iOS9AdaptationTips转载于:https://www.cnblogs.com/zkzzkz/p/5426658.html

javascript知识点记录(2)

1.js 异步加载和同步加载 异步加载模式也叫非阻塞模式&#xff0c;浏览器在下载js的同时&#xff0c;同时还会执行后续的页面处理&#xff0c; 在script标签内&#xff0c;用创建一个script元素&#xff0c;并插入到document中&#xff0c;这样就是异步加载js文件了 //以前的一…

java form的时间格式_SpringMvc接收日期表单提交,自动转换成Date类型方法

User中有birthday(Date)属性&#xff0c;用户注册的时候&#xff0c;选择日期即可&#xff0c;然后提交表单&#xff0c;可spring mvc 报错&#xff0c;400 Bad Request意思是不能把字符串转为Date类型的。实体类中加日期格式化注解DateTimeFormat(pattern "yyyy-MM-dd&q…

Groovy安装与入门实例

Groovy安装与入门实例 摘自: http://blog.csdn.net/dc_726/article/details/8576205 1 Groovy是什么&#xff1f; 来看下官网的介绍&#xff1a;http://groovy.codehaus.org Groovy... is an agile and dynamic language for the Java Virtual Machine builds upon the stren…

Ubuntu设置为命令行登录

rootubuntu:~# vi /etc/default/grub 改: 11 #GRUB_CMDLINE_LINUX_DEFAULT"quiet splash"12 GRUB_CMDLINE_LINUX_DEFAULT"quiet splash text" rootubuntu:~# update-grub rootubuntu:~# reboot 转载于:https://www.cnblogs.com/mylinux/p/5437543.html

java开发平台普元_java开发平台的两种实现模式

从目前国内主流的java开发平台看&#xff0c;主要有两种实现模式&#xff1a;引擎模式及生成源代码模式。引擎模式比较有代表性的是华丹平台(https://www.huadaninfo.com)&#xff0c;生成源代码模式比较有名是的普元平台(http://www.primeton.com)首先说一下引擎模式&#xff…

sde用户下使用sqlplus登录错误ORA-12547: TNS:lost contact

环境&#xff1a;linux oracle arcsde 解决&#xff1a;root用户下增加$ORACLE_HOME/bin/oracle文件的s权限[oraclelocalhost bin]$ chmod s oracle查看权限[oraclelocalhost bin]$ ls -al oracles权限参考 chmod s 可以给文件/目录 设置 suid和sgid转载于:https://www.cnblo…

java版本streamgobbler_java调用本地命令 Runtime class's exec() method

一个简单的定时调用dos命令的例子2,ExecJavac.java 带有异常处理的命令调用例子3,GoodWindowsExec.java 执行windows下的命令&#xff0c;命令作为参数输入StreamGobbler.java4,GoodWinRedirect.java 一个调用命令相对复杂的例子&#xff0c;复合命令StreamRedirectGobbler.jav…

Linux定时任务

最近在做一个SHELL脚本&#xff0c;要求每月1号执行一次。 不管是SHELL脚本&#xff0c;还是定时任务&#xff0c;都是刚接触。今天先记录下定时任务的解决过程&#xff0c;shell脚本的总结等测试无误后写出来。 root以及其他用户可以使用 crontab -e 命令添加定时任务 crontab…

java长连接转短连接_java原生程序redis连接(连接池/长连接和短连接)选择问题...

原标题&#xff1a;java原生程序redis连接(连接池/长连接和短连接)选择问题最近遇到的连接问题我准备从重构的几个程序(redis和mysql)长连接和短连接&#xff0c;以及连接池和单连接等问题用几篇博客来总结下。这个问题的具体发生在java原生程序和redis的交互中。这个问题对我最…

CCTF部分赛题分析

这次算是跟着师傅们全程打完了CCTF的线上赛&#xff0c;一些强队的WriteUp也放了出来。这篇文章主要是想跟着大牛的思路把那些题重新再过一遍。 PWN3 这个是格式化字符串漏洞的题。printf的格式化串直接来自用户输入。 操作流程 用格式化字符串"%7$x"泄漏libc的地址。…

mediawiki mysql_MediaWiki

MediaWiki 最初是由科隆大学的学生及Magnus Manske这位程式开发员设计来编写维基百科的。50而当时是使用以Perl基础的UseModWiki(被维基社群加上外号为”Phase I”)&#xff0c;但後来於2002年1月25日转换至以PHP编写的新版本(”Phase Ⅱ”)。这个维基社群中是十分有名的&#…

20159206 《网络攻防实践》第九周学习总结

20159206《网络攻防实践》第九周学习总结 教材学习内容总结 本周我们学习了教材的第九章和第十章。 第九章介绍了恶意代码安全攻防。首先教材介绍了恶意代码的基础知识&#xff0c;恶意代码指的是使计算机按照攻击者的意图执行以达到恶意目的的指令集。恶意代码包括计算机病毒、…

mysql 操作xm_mysql基本命令使用

启动mysql>net start mysql连接mysql>mysql -u root -h 127.0.0.1 -p password断开mysql连接>qult;查看mysql服务器所有数据库列表>show databases;选择mysql数据库>use database_name;创建数据库>create database database_name;删除数据库>drop databas…