知识大全 Java中的模式--单态
Posted 知
篇首语:仰天大笑出门去,我辈岂是蓬蒿人。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 Java中的模式--单态相关的知识,希望对你有一定的参考价值。
Java中的模式--单态 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
单态定义:
Singleton模式主要作用是保证在Java应用程序中 一个类Class只有一个实例存在
Singleton模式就为我们提供了这样实现的可能 使用Singleton的好处还在于可以节省内存 因为它限制了实例的个数 有利于Java垃圾回收(garbage collection)
使用Singleton注意事项
有时在某些情况下 使用Singleton并不能达到Singleton的目的 如有多个Singleton对象同时被不同的类装入器装载 在EJB这样的分布式系统中使用也要注意这种情况 因为EJB是跨服务器 跨JVM的
单态模式的演化
单态模式是个简单的模式 但是这个简单的模式也有很多复杂的东西
(注意 在这里补充一下 现在单态模式其实有一个写法是不错的见这里 但还是建议看完这篇文章 因为解释的事情是不一样的 这里说的是为什么double checked不能使用 )
一 首先最简单的单态模式 单态模式
import java util *;
class Singleton
private static Singleton instance;
private Vector v;
private boolean inUse;
private Singleton()
v = new Vector();
v addElement(new Object());
inUse = true;
public static Singleton getInstance()
if (instance == null) //
instance = new Singleton(); //
return instance; //
这个单态模式是不安全的 为什么说呢 ?因为没考虑多线程 如下情况
Thread 调用getInstance() 方法 并且判断instance是null 然后进入if模块
在实例化instance之前
Thread 抢占了Thread 的cpu
Thread 调用getInstance() 方法 并且判断instance是null 然后进入if模块
Thread 实例化instance 完成 返回
Thread 再次实例化instance
这个单态已经不在是单态
二 为了解决刚才的问题 单态模式
public static synchronized Singleton getInstance()
if (instance == null) //
instance = new Singleton(); //
return instance; //
采用同步来解决 这种方式解决了问题 但是仔细分析正常的情况下只有第一次时候 进入对象的实例化 须要同步 其它时候都是直接返回已经实例化好的instance不须要同步 大家都知到在一个多线程的程序中 如果同步的消耗是很大的 很容易造成瓶颈
三 为了解决上边的问题 单态模式 加入同步
public static Singleton getInstance()
if (instance == null)
synchronized(Singleton class)
instance = new Singleton();
return instance;
同步改成块同步 而不使用函数同步 但是仔细分析
又回到了模式一的状态 再多线程的时候根本没有解决问题
四 为了对应上边的问题 单态模式 也就是很多人采用的Double checked locking
public static Singleton getInstance()
if (instance == null)
synchronized(Singleton class) //
if (instance == null) //
instance = new Singleton(); //
return instance;
这样 模式一中提到的问题解决了 不会出现多次实例化的现象
当第一次进入的时候 保正实例化时候的单态 在实例化后 多线程访问的时候直接返回 不须要进入同步模块 既实现了单态 又没有损失性能 表面上看我们的问题解决了 但是再仔细分析
我们来假象这中情况
Thread :进入到// 位置 执行new Singleton() 但是在构造函数刚刚开始的时候被Thread 抢占cpu
Thread :进入getInstance() 判断instance不等于null 返回instance
(instance已经被new 已经分配了内存空间 但是没有初始化数据)
Thread :利用返回的instance做某些操做 失败或者异常
Thread :取得cpu初始化完成
过程中可能有多个线程取到了没有完成的实例 并用这个实例作出某些操做
-----------------------------------------
出现以上的问题是因为
mem = allocate(); //分配内存
instance = mem; //标记instance非空
//未执行构造函数 thread 从这里进入
ctorSingleton(instance); //执行构造函数
//返回instance
------------------------------------------
五 证明上边的假想是可能发生的 字节码是用来分析问题的最好的工具 可以利用它来分析下边一段程序 (为了分析方便 所以渐少了内容)
字节码的使用方法见这里 利用字节码分析问题
class Singleton
private static Singleton instance;
private boolean inUse;
private int val;
private Singleton()
inUse = true;
val = ;
public static Singleton getInstance()
if (instance == null)
instance = new Singleton();
return instance;
得到的字节码
;asm code generated for getInstance
D B mov eax [ C ] ;load instance ref
D B test eax eax ;test for null
D B jne D D
D B mov eax C h
D BE call EF F ;allocate memory
D C mov [ C ] eax ;store pointer in
;instance ref instance
;non null and ctor
;has not run
D C mov ecx dword ptr [eax]
D CA mov dword ptr [ecx] ;inline ctor inUse=true;
D D mov dword ptr [ecx+ ] ;inline ctor val= ;
D D mov ebx dword ptr ds:[ C h]
D DD jmp D B
上边的字节码证明 猜想是有可能实现的
六 好了 上边证明Double checked locking可能出现取出错误数据的情况 那么我们还是可以解决的
public static Singleton getInstance()
if (instance == null)
synchronized(Singleton class) //
Singleton inst = instance; //
if (inst == null)
synchronized(Singleton class) //
inst = new Singleton(); //
instance = inst; //
return instance;
利用Double checked locking 两次同步 中间变量 解决上边的问题
(下边这段话我只能简单的理解 翻译过来不好 所以保留原文 list 是上边的代码 list 是下边的
The code in Listing doesn t work because of the current definition of the memory model
The Java Language Specification (JLS) demands that code within a synchronized block
not be moved out of a synchronized block However it does not say that
code not in a synchronized block cannot be moved into a synchronized block
A JIT piler would see an optimization opportunity here
This optimization would remove the code at
// and the code at // bine it and generate the code shown in Listing :)
list
public static Singleton getInstance()
if (instance == null)
synchronized(Singleton class) //
Singleton inst = instance; //
if (inst == null)
synchronized(Singleton class) //
//inst = new Singleton(); //
instance = new Singleton();
//instance = inst; //
return instance;
If this optimization takes place you have the same out of order write problem we discussed earlier
如果这个优化发生 将再次发生上边提到的问题 取得没有实例化完成的数据
以下部分为了避免我翻译错误误导打家 保留原文
Another idea is to use the keyword volatile for the variables inst and instance
According to the JLS (see Resources) variables declared volatile are supposed to
be sequentially consistent and therefore not reordered
But o problems occur with trying to use volatile to fix the problem with
double checked locking:
The problem here is not with sequential consistency
Code is being moved not reordered
Many JVMs do not implement volatile correctly regarding sequential consistency anyway
The second point is worth expanding upon Consider the code in Listing :
Listing Sequential consistency with volatile
class test
private volatile boolean stop = false;
private volatile int num = ;
public void foo()
num = ; //This can happen second
stop = true; //This can happen first
//
public void bar()
if (stop)
num += num; //num can == !
//
According to the JLS because stop and num are declared volatile
they should be sequentially consistent This means that if stop is ever true
num must have been set to
However because many JVMs do not implement the sequential consistency feature of volatile
you cannot count on this behavior
Therefore if thread called foo and thread called bar concurrently
thread might set stop to true before num is set to
This could lead thread to see stop as true but num still set to
There are additional problems with volatile and the atomicity of bit variables
but this is beyond the scope of this article
See Resources for more information on this topic
简单的理解上边这段话 使用volatile有可能能解决问题 volatile被定义用来保正一致性 但是很多虚拟机并没有很好的实现volatile 所以使用它也会存在问题
最终的解决方案
( ) 单态模式 使用同步方法
( ) 放弃同步 使用一个静态变量 如下
class Singleton
private Vector v;
private boolean inUse;
private static Singleton instance = new Singleton();
private Singleton()
v = new Vector();
inUse = true;
//
public static Singleton getInstance()
return instance;
但使用静态变量也会存在问题 问题见 这篇文章
而且如在文章开头提到的 使用EJB跨服务器 跨JVM的情况下 单态更是问题
cha138/Article/program/Java/gj/201311/27326相关参考
登记式单态类 登记式单态类是GoF为了克服饿汉式单态类及懒汉式式单态类均不可继承的缺点而设计的作者把他们的例子翻译为爪哇语言并将它自己实例化的方式从懒汉式改为饿汉式只是它的子类实例化的方式只能是
JAVA的设计模式我想大家都知道但每个人的理解并不相同我在这里只是阐述我的观点要是与您的观点不同请您原谅和提出您的宝贵意见 为了把命令模式讲清楚我要举一个大家都影象深刻的例子以便大家的理解那
Java开发中的23种设计模式 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  
知识大全 Java I/O 包中的Decorator模式介绍
JavaI/O包中的Decorator模式介绍 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!JDK
Java中的静态代理和动态代理 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 代理模式主要有两种
当然也可以结合工厂模式来创建AbstractSpoon实例 在Java中Prototype模式变成clone()方法的使用由于Java的纯洁的面向对象特性 使得在Java中使用设计模式变得很自
Java设计模式-----Command模式 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 源自
Java设计模式-----State模式 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 源自
Java与模式之单例模式 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 单例模式(Singlet
Java设计模式之Strategy模式 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! Strat