单例模式:
保证一个类只有一个实例, 并提供一个全局访问点。(可以说是最简单的模式, 从零单排冲天梯)
类图:
抽象实现:
1. 懒汉模式 (懒得判断是否已经实例化, 先进行实例化)
package com.wenniuwuren.singleton;
public class Singleton {
// 懒汉模式
/**
* 私有且唯一的属性
*/
private static Singleton uniqueInstance = new Singleton();
/**
* 私有构造器保证不能被继承
*/
private Singleton() {
}
/**
* 全局访问点 static的修饰至关重要--提供给外部在不能实例化内部代码的时候通过类名访问内部public方法
*/
public static Singleton getInstance() {
return uniqueInstance;
}
}
适用于对程序性能有较大要求的地方, 如果用饱汉模式(详情见下文)要对线程加同步锁降低系统性能。
2. 饱汉模式(采用了volatile和同步块来保证并发安全性, 不像上面的懒汉模式直接就实例化了, 因为饱汉模式存在着判断和赋值,所以必须加上安全机制保障并发的正确性。 例如:线程A判断uniqueInstance为null进入方法, 然后new了实例, 但是还没赋值给uniqueInstance, 这时CPU把时间给了线程B, 此时的uniqueInstance还未赋值所以又new了一次实例, 那么这就破坏了单例模式了)
package com.wenniuwuren.singleton;
public class Singleton {
// 饱汉模式
/**
* 私有且唯一的属性
* volatile修饰符保证变量仅存在于内存, 每个线程仅在内存中共享该变量, 从而保证了并发的安全性
*/
private volatile static Singleton uniqueInstance = null;
/**
* 私有构造器保证不能被继承
*/
private Singleton() {
}
/**
* 全局访问点
*/
public static Singleton getInstance() {
if (uniqueInstance == null) {
// 为空时才进行创建实例(延迟创建实例有助于节省不必要的资源占用)
synchronized (Singleton.class) {
if (uniqueInstance == null) {
return uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
当然如果系统对性能要求不高, 饱汉模式可以不像上面那么复杂, 直接在getInstance()方法上加同步修饰字段synchronized即可。
但是上面的方法虽然已经把同步代码块缩减到最小, 但是还是对性能有一点影响, 接下来介绍另一种保障线程安全的方法并且不使用同步代码块和volatile字段修饰。
public class Singleton {
private Singleton(){}
/**
* 类级的内部类,只有被调用到时才会实例化
*/
private static class SingletonHolder{
private static Singleton instance = new Singleton();
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
应用场景:
- 网站的计数器, 不然并发计数访客什么的数量肯定会乱
- 应用程序的日志, 并发写日志不控制安全性日志重复写入多次
- Spring中的Bean默认也是单例的
参考书籍:
《设计模式:可复用面向对象软件的基础》
《Java并发编程实战》
原文:http://blog.csdn.net/wenniuwuren/article/details/42656701