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

   日期:2020-11-09     浏览:139    评论:0    
核心提示:单例模式单例模式(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后让方法变为同步方法,实现在多线程下的线程安全,但仍存在问题。
因为每次调用方法获取实例都会进行加锁,如果线程过多就会影响效率。

再做一点优化:

	
	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("不允许创建多个实例");
		}
	}
 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服