欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

单例模式饿汉式与懒汉式,内部类实现单例模式

程序员文章站 2022-03-26 22:24:42
单例模式单例模式(Singleton Pattern)是指确保一个类在任何情况下都绝对持有一个实例,并提供一个全局访问点。饿汉式单例模式就是在类加载的时候就立即初始化,并且创建单例对象。绝对的线程安全public class HungrySingleton {//private static final HungrySingleton hungrySingleton = new HungrySingleton();//静态代码块private static final HungryS...

单例模式

单例模式(Singleton Pattern)是指确保一个类在任何情况下都绝对持有一个实例,并提供一个全局访问点。

饿汉式单例模式

就是在类加载的时候就立即初始化,并且创建单例对象。绝对的线程安全

public class HungrySingleton {
	//private static final HungrySingleton hungrySingleton = new HungrySingleton();
	
	//静态代码块
	private static final HungrySingleton hungrySingleton;
	static {
		hungrySingleton = new HungrySingleton();
	}
	
	private HungrySingleton() {}
	
	public static HungrySingleton getInstance() {
		return hungrySingleton;
	}
}

由于不加锁,执行效率较高。
但在类加载的时候就已经实例化,不管用不用,都在占用内存,造成资源浪费。

懒汉式单例模式

就是在外部类调用的时候才会初始化。

public class LazySingleton {

	private static LazySingleton lazy = null;
	private LazySingleton() {
	}

		 public static LazySingleton getInstance() {
	 	//单线程安全
	 	if(lazy==null) {
	 		lazy = new LazySingleton();
	 	}
	 	return lazy;
	}
}

该方法仅在单线程下线程安全。
做一点优化:

public synchronized static LazySingleton getInstance() {
		if (lazy == null) {
			lazy = new LazySingleton();
		}
		return lazy;
	}

加synchronized后让方法变为同步方法,实现在多线程下的线程安全,但仍存在问题。
因为每次调用方法获取实例都会进行加锁,如果线程过多就会影响效率。

再做一点优化:

	/**
	 * 双重检查锁的单例模式
	 * @return
	 */
	public static LazySingleton getInstance() {
		if(lazy==null) {
			synchronized(LazySingleton.class) {
				if(lazy==null) {
					lazy=new LazySingleton();
				}
			}
		}
		return lazy;
	}

采用双重判断并加锁机制来实现多线程下线程安全。

但这样还是使用了synchronized关键字,总归要上锁,对程序性能还是存在一定的影响。

用内部类来实现单例模式

	public class LazyInnerClassSingleton {
	
	private LazyInnerClassSingleton() {}
	
	public static final LazyInnerClassSingleton getInstance() {
		//再返回结果之前,一定会先加载内部类
		return LazyHolder.LAZY;
	}
	
	//默认不加载
	private static class LazyHolder{
		private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton();
	}
}

这个形式兼顾了饿汉式模式的内存浪费问题和synchronized的性能问题。

这样就完美了吗?

当然不是,单例模式的构造函数除了加private关键字外,没有其他任何处理,尝试使用反射来调用其构造函数。

public static void main(String[] args) {
		try {
			Class<?> clazz = LazyInnerClassSingleton.class;
			
			//通过反射获取私有的构造方法
			Constructor<?> c = clazz.getDeclaredConstructor(null);
			
			//强制访问
			c.setAccessible(true);
			
			//暴力初始化
			Object o1 = c.newInstance();
			Object o2 = c.newInstance();
			System.out.println(o1==o2);
		}catch(Exception e) {
			e.printStackTrace();
		}
	}

结果打印为false,这并不是单例模式希望看到的,对原来的构造函数再做一些限制,一旦出现多次重复创建,则直接抛出异常。

	private LazyInnerClassSingleton() {
		if(LazyHolder.LAZY!=null) {
			throw new RuntimeException("不允许创建多个实例");
		}
	}

本文地址:https://blog.csdn.net/Zhangxg0206/article/details/109562335