单例模式饿汉式与懒汉式,内部类实现单例模式
程序员文章站
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
上一篇: 讲真,有好奇
下一篇: JDBC工具类_JdbcUtils