您的位置:首页 > 编程语言 > Java开发

Java学习笔记-单件模式

2014-02-18 09:23 148 查看
来源于headfirst设计模式

单例模式的性能指标:lazy(是否延迟实例化),线程安全

一、延迟实例化,同步(synchronized)方法-->由于是单例更需要考虑处理问题需要考虑的同步问题,延迟实例化主要是面向资源敏感的对象

public class Singleton {

private static Singleton uniqueinstance;//唯一的实例变量

private Singleton() {//私有的初始化方法
}

public static synchronized Singleton getInstance() {
//实例的获取方法,将普通的初始化方法变为获得方法
if (uniqueinstance== null) {
uniqueinstance= new Singleton();//直接在类内部初始化
}
return instance;
}
}


二、直接实例化(静态工厂方法)

public class Singleton {

private static Singleton uniqueInstance = new Singleton();
//直接创建单例
private Singleton() {
}

public static Singleton getInstance() {

return uniqueInstance;
}
}


三、双重检验加锁,双重检查锁定模式首先验证锁定条件(第一次检查),只有通过锁定条件验证才真正的进行加锁逻辑并再次验证条件(第二次检查)。-->用来减少并发系统中竞争和同步的开销。[http://zh.wikipedia.org/wiki/%E5%8F%8C%E9%87%8D%E6%A3%80%E6%9F%A5%E9%94%81%E5%AE%9A%E6%A8%A1%E5%BC%8F]

public class Singleton {

private volatile static Singleton instance = null;//volatile变量

private Singleton() {
}

public static Singleton getInstance() {

if (instance == null) {//只有首次初始化时才用到了同步模块,避免了同步对资源的浪费
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}


volatile变量的作用[参考:http://blog.csdn.net/orzorz/article/details/4319055]

用在多线程,为了同步变量。在Java内存模型中,有main memory,每个线程也有自己的memory (例如寄存器)。为了性能,一个线程会在自己的memory中保持要访问的变量的副本。这样就会出现同一个变量在某个瞬间,在一个线程的memory中的值可能与另外一个线程memory中的值,或者main memory中的值不一致的情况。
一个变量声明为volatile,就意味着这个变量是随时会被其他线程修改的,因此不能将它cache在线程memory中。synchronized的优势在于其可以把方法或者代码块变为原子操作,而volatile无法。

四、枚举单例,上面的方法都有一个问题就是反序列化,破坏了单例的特性,你可以去查询使用readResolve(),但比较麻烦,推荐使用Java的这个新特性——枚举类型。它具有内置的序列化支持和线程安全支持。

public
enum
EasySingleton{


  INSTANCE;

}

在 java 垃圾回收中,描述了jvm运行时刻内存的分配。其中有一个内存区域是jvm虚拟机栈,每一个线程运行时都有一个线程栈,线程栈保存了线程运行时候变量值信息。当线程访问某一个对象时候值的时候,首先通过对象的引用找到对应在堆内存的变量的值,然后把堆内存变量的具体值load到线程本地内存中,建立一个变量副本,之后线程就不再和对象在堆内存变量值有任何关系,而是直接修改副本变量的值,在修改完之后的某一个时刻(线程退出之前),自动把线程变量副本的值回写到对象在堆中变量。这样在堆中的对象的值就产生变化了。

[/article/4878212.html]

五、各种优化

/**
* 基于内部类的单例模式  Lazy  线程安全
* 优点:
* 1、线程安全
* 2、lazy
* 缺点:
* 1、待发现
*
* @author laichendong
* @since 2011-12-5
*/
public class SingletonFive {

/**
* 内部类,用于实现lzay机制
*/
private static class SingletonHolder{
/** 单例变量  */
private static SingletonFive instance = new SingletonFive();
}

/**
* 私有化的构造方法,保证外部的类不能通过构造器来实例化。
*/
private SingletonFive() {

}

/**
* 获取单例对象实例
*
* @return 单例对象
*/
public static SingletonFive getInstance() {
return SingletonHolder.instance;
}

}

http://www.cnblogs.com/coffee/archive/2011/12/05/inside-java-singleton.html
这种方式利用静态内部类的优势,既是后实例化的又是线程安全的。

引申阅读:/article/4139424.html

http://www.ibm.com/developerworks/cn/java/j-jtp06197.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: