单例模式 大家都不陌生、但是写出一个让人满意的单例 并不是那么容易的。
从另一个角度来分析单例模式 方便大家理解。
单例模式:只能创建出类的一个对象 也是唯一的一个对象。
怎么保障只能创建出一个类对象呢?
首先想到的是静态 静态对象是属于类的。所以能保证静态对象的唯一。
其次屏蔽类自身具有的构造方法。 这样就能屏蔽这种创建类对象的方式。
类名 对象名 = new 类名()
第一:屏蔽构造方法,设置成private的。 下面是外部类使用构造方法创建对象的报错信息
SingletonX singletonTest = new SingletonX();
【The constructor SingletonX() is not visible】
第二:自己内部new出一个 自己的对象唯一的对象 返回。
=============================下面是V1.0版本================================
public class SingletonX {
//私有化的构造方法,保证外部的类不能通过构造器来实例化
private SingletonX() {}
//单例 实例变量
private static SingletonX singleton = null;
//获取单例对象实例 对外提供
public static SingletonX getInstance(){
if(singleton==null)
singleton = new SingletonX();
return singleton;
}
}
=============================下面是V2.0版本================================
上面的代码在多线程的环境中不是线程安全的。
等当两个线程进入if (instance == null)时,两个线程都判断instance为空,接下来就会得到两个实例了。这不是我们想要的单例。
为了保证线程安全。使用synchronized 修饰一下
public static synchronized SingletonX getInstance(){
}
此方法是可以解决问题。但是仔细想一想 其实只需要在第一次调用getInstance()的时候加锁就可以了。这样把synchronized 加在方法上会导致每次调用getInstance方法。
把synchronized 加到代码块上试一试吧
=============================下面是V2.5版本================================
//获取单例对象实例 对外提供
public static SingletonX getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
//再次判断是否为空 防止上面多线程的时候有多个线程进入了等待synchronized 如不再次进行为空判断依然会出现多个实例。
if (instance == null) {
instance = new Singleton();
}
}
}
return singleton;
=============================下面是V2.5版本================================
不过又听说java平台内存模型中有一个叫“无序写”(out-of-order writes)的机制。
instance = new Singleton(); 这行其实做了两个事情:
1、调用构造方法,创建了一个实例。
2、把这个实例赋值给instance这个实例变量。可问题就是,这两步jvm是不保证顺序的。也就是说。可能在调用构造方法之前,instance已经被设置为非空了。
synchronized 能保障同一时间只有一个线程进入同步块。但是不能保证每次都能完整执行同步块,也就是执行了一部分就退出,让给其他线程来执行。 A线程执行了上面说的第2步退出
此时instance 不为空了,我也不知道它现在是一个什么值? B线程进来判断不为空 返回了一个没有调用构造方法实例出来的一个值。紧接着A线程继续调用构造方法返回真正的单例对象。
解决方案:
就是要保障instance = new Singleton() 这个搞成原子性的。 引入一个Temp变量来保存创建出来的实例对象,如果没有完整创建,退出。B线程进来instance 依然是Null。
//获取单例对象实例
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) { //1
Singleton temp = instance; //2
if (temp == null) {
synchronized (Singleton.class) { //3
temp = new Singleton(); //4
}
instance = temp; //5
}
}
}
System.out.println("我是解决无序写懒汉式单例!");
return instance;
}
=============================下面是V3.0版本================================
虽然实现了但是很乱,精简一下代码换个思路。
//饿汉式
public class Singleton {
//单例变量 ,static的,在类加载时进行初始化一次,保证线程安全
private static Singleton instance = new Singleton();
//私有化的构造方法,保证外部的类不能通过构造器来实例化。
private Singleton() {}
//获取单例对象实例
public static Singleton getInstance() {
System.out.println("我是饿汉式单例!");
return instance;
}
}
代码分析:饿汉式单例,意思就是预先声明Singleton对象,这样带来的一个缺点就是:如果构造的单例很大,构造完又迟迟不使用,会导致资源浪费。
==========继续改进调用getInstance方法时再进行构造方法初始化对V4.0===========
//内部类实现懒汉式
public class Singleton {
private static class SingletonHolder{
//单例变量
private static Singleton instance = new Singleton();
}
//私有化的构造方法,保证外部的类不能通过构造器来实例化。
private Singleton() {}
//获取单例对象实例
public static Singleton getInstance() {
System.out.println("我是内部类单例!");
return SingletonHolder.instance;
}
}
懒汉式(避免上面的资源浪费)、线程安全、代码简单。因为java机制规定,
内部类SingletonHolder只有在getInstance()方法第一次调用的时候才会被加载(实现了lazy),
而且其加载过程是线程安全的(实现线程安全)。内部类加载的时候实例化一次instance
SingletonHolder是私有静态内部类,所以不会被其他类知道,同样,static语义也要求不会有多个实例存在。并且,JSL规范定义,类的构造必须是原子性的,非并发的,因此不需要加同步块。同样,由于这个构造是并发的,所以getInstance()也并不需要加同步。
欢迎探讨:QQ 350355139 设计模式一次搞定
参考资料:
http://blog.163.com/yanjingyu_happy/blog/static/111639566201364115047132/
http://devbean.blog.51cto.com/448512/203501/
分享到:
相关推荐
由于在项目中单例模式户经常用到,所以可以将其写成宏放头文件里,这样就可以两行代码搞定单例
Easy搞定设计模式.pdf
自己整理的简单,清晰,易于理解学习设计模式文档。如果你是新手。看完这三十多页的PPT,相信你可以轻松搞定常用的设计模式。
最新的Git与Github巨作课程,课程内容主旨分成了Git&Github极速入门与攻坚实战课程两部分,可以理解为一个是课程的详细教学篇,和一个精华缩减的集合。Git与Github教程详细介绍了Git的...一次性搞定Git与Github的学习。
iis 安装文件 不用光盘 iis 安装文件 一次搞定
XP计算机名_IP_网关_DNS一次搞定
window2003制作漫游用户,非常简单,按照步奏,一次搞定
给大家分享一套课程,Java高级面试突围课 ,一次搞定Java中高级面试的必考点视频教程,希望对大家面试有帮助。
STM32f103各种外围电路合集,一次下载搞定!
考研英语作文万能模板一次搞定.doc
考研英语作文的万能模板一次搞定.doc
今天又做了一个基于单例和抽象工厂及sql动态参数的CodeSmith多层模板,用到了单例设计模式和抽象工厂模式接口,根据个人业务需要可以进行动态修改生成自己所需要的代码,搭建.net多层代码不用1个小时就搞定。
考研英语作文万能模板(一次搞定).doc
Java高级面试突围课 ,一次搞定Java中高级面试的必考点,本课采用大厂多轮面试形式贯穿主线,内容涵盖Java中高级面试的必考点、高频点、加薪点。同时融合讲师多年阿里字节考官经验,通过真实模拟不同面试场景,将面试...
android开发环境的配置, 里面图文教程 ,跟着教程做,可以一次搞定!
一周搞定系列之模电全集 模电基本 ppt
搞定面试官:咱们从头到尾再说一次 Java 垃圾回收(csdn)————程序
discuz微信登录插件西瓜微信超级好用微信授权登录一次搞定支持手机版。自动生成账号,避免重名。