【设计模式】单例模式
单例模式
优点
- 可以保证内存中只有一个实例,减少了内存的开销
- 可以避免对资源的多重占用
- 可以优化和共享资源的访问
缺点
- 扩展难,违背了开闭原则
- 不利于调试(并发测试中)
- 功能设计不合理就会违背单一职责原则
饿汉式单例模式
/**
* 饿汉式单例:使用静态块机制,在对象类加载的时候就实例化(类还没加载就实例)。
* 优点:可以保证绝对线程安全,执行效率高
* 缺点:当系统中有大批量的单例对象存在,可能会造成大量内存的浪费。
*/
class HungrySingleton{
private static final HungrySingleton hungrySingleton = new HungrySingleton();
private HungrySingleton(){
}
public static HungrySingleton getInstance(){
return hungrySingleton;
}
}
//第二种写法
class HungrySingleton{
private static final HungrySingleton hungrySingleton;
//使用静态块
static{
hungrySingleton = new HungrySingleton();
}
private HungrySingleton(){
}
public static HungrySingleton getInstance(){
return hungrySingleton;
}
}
懒汉式单例模式
/**
* 懒汉式单例:被使用时才初始化。
* 优点:
* 缺点:
*/
class LazySingleton{
//volatile防止指令重排序
private volatile static LazySingleton instance;
private LazySingleton(){
}
public static LazySingleton getInstance(){
//判断是否要阻塞
if (instance == null){
synchronized (LazySingleton.class){
//判断是否要实例化对象
if (instance == null){
instance = new LazySingleton();
//指令重排问题
}
}
}
return instance;
}
}
优化单例模式
静态内部类
/**
* 静态内部类
* 优点:屏蔽了饿汉式的内存损耗和懒汉式的synchronized性能消耗
* 缺点:可以通过(反射/反序列化)的方式破坏单例模式
*/
class StaticInnerClassSingleton{
//使用StaticInnerClassSingleton时,默认先初始化内部类
//如果没使用,内部类不加载
private StaticInnerClassSingleton(){
}
//static使单例模式的空间共享,保证这个方法不会被重写、重载。
public static StaticInnerClassSingleton getInstance(){
return LazyHolder.staticInnerClassSingleton;
}
//java本身语言特点,默认不加载内部类
private static class LazyHolder{
private static final StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();
}
}
/**
* 优化反射破坏后的静态内部类
* 优点:屏蔽了饿汉式的内存损耗和懒汉式的synchronized性能消耗,不能通过反射的方式进行破坏。
* 缺点:可以通过反序列化的方式破坏单例,在构造函数中抛出异常,不够完美。
*/
class StaticInnerClassSingleton{
//使用StaticInnerClassSingleton时,默认先初始化内部类
//如果没使用,内部类不加载
private StaticInnerClassSingleton(){
if(LazyHolder.staticInnerClassSingleton != null){
throw new RuntimeException("不允许创建多个实例");
}
}
//static使单例模式的空间共享,保证这个方法不会被重写、重载。
public static StaticInnerClassSingleton getInstance(){
return LazyHolder.staticInnerClassSingleton;
}
//java本身语言特点,默认不加载内部类
private static class LazyHolder{
private static final StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();
}
}
/**
* 优化(反射/反序列化)破坏后的静态内部类
* 优点:屏蔽了饿汉式的内存损耗和懒汉式的synchronized性能消耗,不能通过(反射/反序列化)的方式进行破坏。
* 缺点:在构造函数中抛出异常,不够完美。
*/
class StaticInnerClassSingleton implements Serializable{
//使用StaticInnerClassSingleton时,默认先初始化内部类
//如果没使用,内部类不加载
private StaticInnerClassSingleton(){
if(LazyHolder.staticInnerClassSingleton != null){
throw new RuntimeException("不允许创建多个实例");
}
}
//static使单例模式的空间共享,保证这个方法不会被重写、重载。
public static StaticInnerClassSingleton getInstance(){
return LazyHolder.staticInnerClassSingleton;
}
//java本身语言特点,默认不加载内部类
private static class LazyHolder{
private static final StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();
}
private Object readResolve(){
return LazyHolder.staticInnerClassSingleton;
}
}
反射破坏单例
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Constructor<StaticInnerClassSingleton> constructor = StaticInnerClassSingleton.class.getDeclaredConstructor();
constructor.setAccessible(true);
//通过反射创建的实例
StaticInnerClassSingleton instance1 = constructor.newInstance();
//正常获取的实例
StaticInnerClassSingleton instance2 = StaticInnerClassSingleton.getInstance();
System.out.println(instance1 == instance2); //false
}
public T newInstance(Object ... initargs)
throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException
{
......
//官方不支持反射创建enum类型的
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
throw new IllegalArgumentException("Cannot reflectively create enum objects");
......
}
枚举式单例
/**
* 枚举式单例
* 优点:屏蔽了饿汉式的内存损耗和懒汉式的synchronized性能消耗,不能通过(反射/反序列化)的方式进行破坏。
* 缺点:在类加载时将所有的对象初始化放在类内存中,和饿汉式单例差不多,不适合大量创建单例对象。
*/
enum EnumSingleton{
INSTANCE;
private Object data;
public Object getData(){
return data;
}
public void setData(Object data){
this.data = data;
}
public static EnumSingleton getInstance(){
return INSTANCE;
}
}
反序列化破坏单例
public static void main(String[] args) throws IOException, ClassNotFoundException {
StaticInnerClassSingleton instance1 = StaticInnerClassSingleton.getInstance();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("testSerializable"));
oos.writeObject(instance1);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("testSerializable"));
StaticInnerClassSingleton o = (StaticInnerClassSingleton) ois.readObject();
System.out.println(instance == o);
}
容器式单例
/**
* 容器式单例
* 优点:适用于大量单例对象的创建,便于管理。
* 缺点:线程不是安全的。
*/
class ContainerSingleton{
private ContainerSingleton(){}
private static Map<String, Object> ioc = new ConcurrentHashMap<String, Object>();
public static Object getBean(String className){
synchronized (ioc){
if (!ioc.containsKey(className)){
Object obj = null;
try {
obj = Class.forName(className).newInstance();
ioc.put(className, obj);
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}else {
return ioc.get(className);
}
}
}
}
通过clone破坏单例
public static void main(String[] args) throws CloneNotSupportedException {
StaticInnerClassSingleton singleton = StaticInnerClassSingleton.getInstance();
StaticInnerClassSingleton clone = singleton.clone();
System.out.println(singleton == clone);
}
class StaticInnerClassSingleton implements Serializable,Cloneable{
//使用StaticInnerClassSingleton时,默认先初始化内部类
//如果没使用,内部类不加载
private StaticInnerClassSingleton(){
if(LazyHolder.staticInnerClassSingleton != null){
throw new RuntimeException("不允许创建多个实例");
}
}
//static使单例模式的空间共享,保证这个方法不会被重写、重载。
public static StaticInnerClassSingleton getInstance() {
return LazyHolder.staticInnerClassSingleton;
}
//重写clone方法,放在复制破坏单例。
@Override
protected StaticInnerClassSingleton clone() throws CloneNotSupportedException {
return LazyHolder.staticInnerClassSingleton;
}
//java本身语言特点,默认不加载内部类
private static class LazyHolder{
private static final StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();
}
private Object readResolve(){
return LazyHolder.staticInnerClassSingleton;
}
}
线程单例实现ThreadLocal
/**
* 线程单例实现ThreadLocal
* 优点:在单个线程中是唯一的
* 缺点:不能保证全局对象唯一
*/
class ThreadLocalSingleton{
private static final ThreadLocal<ThreadLocalSingleton> threadLocalInstance = new ThreadLocal<ThreadLocalSingleton>(){
@Override
protected ThreadLocalSingleton initialValue() {
return new ThreadLocalSingleton();
}
};
private ThreadLocalSingleton(){}
public static ThreadLocalSingleton getInstance(){
return threadLocalInstance.get();
}
}
单例模式的应用
JDK中的Runtime类
Spring中的BeanFactory的getBean()方法