核心作用:
保证一个类只有一个实例,并且提供一个访问该实例的全局访问点
常见应用场景:
单例模式的优点:
- 由于单例模式只生成一个实例,减少了系统的开销,当一个对象的产生需要比较多的资源师,如:读取配置,产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决
- 单例模式可以在系统设置全局的访问点,优化环共享资源访问,例如可以设计一个单例类负责所有数据表的映射处理
常见的五种单例模式实现方式:
- 饿汉式(线程安全,调用效率高,不能延时加载)
解释:饿汉式单例代码中,static变量会在类装载是初始化,此时也不会涉及多个线程对象访问该对象的问题。虚拟保证只会装载一次该类,肯定不会发生并发访问的问题。因此不需要synchronized关键字
问题:如果只是加载本类,而不是要调用getInstance(),甚至永远没有调用,则会造成资源浪费
package com.lp.singleton;
/*测试饿汉式单例模式*/
/*当类实例化的*/
public class SingletonDemo1 {
// ctrl + m 快捷键 优化界面
// 重点:类初始化时立即加载
private static SingletonDemo1 instance = new SingletonDemo1();
//这个函数规定了外部不能实例化这个类的对象
private SingletonDemo1(){
}
//方法没有同步,调用效率高
public static SingletonDemo1 getInstance(){
return instance;
}
}
- 懒汉式(线程安全,调用效率不高,可以延时加载)
问题:资源利用率高了,但是,每次调用getInstance方法都要同步,并发效率低
package com.lp.singleton;
/*测试懒汉式单例模式*/
public class SingletonDemo2 {
// ctrl + m 快捷键 优化界面
// 重点:类初始化时不加载
private static SingletonDemo2 s;
//这个函数规定了外部不能实例化这个类的对象
private SingletonDemo2(){
}
//方法同步,调用效率低
public static synchronized SingletonDemo2 getInstance(){
if(s == null){
s = new SingletonDemo2();
}
return s;
}
}
- 双重检测锁式(由于JVM底层内部模型原因,偶尔会出问题,不建议使用)
package com.lp.singleton;
/*这个模式不建议用*/
public class SingletonDemo3 {
private static SingletonDemo3 instance = null;
public static SingletonDemo3 getInstance(){
if(instance == null){
SingletonDemo3 sc ;
synchronized(SingletonDemo3.class){
sc = instance;
if(sc == null){
synchronized(SingletonDemo3.class){
if(sc == null){
sc = new SingletonDemo3();
}
}
instance = sc;
}
}
}
return instance;
}
private SingletonDemo3(){
}
}
- 静态内部类式(线程安全,调用效率高 , 可以延时加载)
要点:1:外部类没有static属性,则不会像饿汉式那样立即加载对象
2:只有真正调用getInstance() ,才会加载静态内部类,加载类时线程是安全的,instance是static final类型,保证了内存中只有这样一个实例存在,而且只能被赋值一次,从而保证了线程安全性.
3:兼备了并发高效调用和延迟加载的优势!
package com.lp.singleton;
//集合了线程安全 高效调用 延时加载 三个有点
public class SingletonDemo4 {
private static class SingletonClassInstance{
private static final SingletonDemo4 instance = new SingletonDemo4();
}
private SingletonDemo4(){
}
public static SingletonDemo4 getInstance(){
return SingletonClassInstance.instance;
}
}
- 枚举单例(线程安全,调用效率高,不能延时加载 )
优点: 1:实现简单
2:枚举本身就是单例模式,由JVM从根本上提供保障!避免通过反射和反序列化的漏洞
package com.lp.singleton;
/*测试枚举式实现单例模式*/
/*唯一缺点:没有延时加载的效果*/
/*防止反射和发序列化漏洞*/
public enum SingletonDemo5 {
//这个枚举元素,本身就是单例对象!
INSTANCE;
//添加自己需要的操作
public void singletionOperation(){
}
}
如何选用:
--单例对象 占用资源 少,不需要 延时加载:
- 枚举式 好于 饿汉式
--单例对象 占用资源 大,需要 延时加载:
- 静态内部类 好于 懒汉式
来源:https://www.cnblogs.com/lipeng0824/p/4418165.html