Java设计模式之单例模式,完整到不敢想象

编程入门 行业动态 更新时间:2024-10-10 13:21:03

1、单例模式

作用:保证一个类只有一个实例,并且提供一个访问该实例的全局访问入口

单例模式的常用

1.Windows的任务管理器
2.Windows的回收站,也是一个单例应用
3.项目中的读取配置文件的对象
4.数据库的连接池
5.Servlet中的Application Servlet
6.Spring中的Bean默认也是单例的
7.SpringMVC Struts中的控制器

单例模式的优点

1.由于单例模式只生成一个实例,减少了系统给的性能开销,当一个对象需要产生时,当时消耗的资源较多。那么产生对象时构建的方式就可以通过单例去构建。
2.单例模式存在全局访问点,所以可以优化共享资源访问。

 

常见的单例模式的构建方法

1.饿汉式:线程安全 调用率高  但是不能延迟加载
2.懒汉式:线程安全 调用率不高 但是可以延迟加载
3.双重检测(double check )
4.静态内部类(线程安全 可以延迟加载)
5.枚举单例 线程安全 不可以延迟加载

 

2、代码案例展示

饿汉式

/*** 饿汉式:*      类只要被加载就会被加载全局变量,所以饿汉式,会被及时加载。(没有懒加载 )*      并且存在天然的线程安全问题。* @author 码歌老薛* @date 创建时间 猴年马月* @version 1.0*/ public class SingleHungry { //提供静态的全局变量 作为访问该类实例的入口 private static SingleHungry sh = new SingleHungry(); /*** 构造器私有 无法创建对象*/ private SingleHungry(){ } /*** 对外提供get方法获取 该类的实例* @return*/ public static SingleHungry getInstance(){ return sh; } } 

懒汉式

 

/** * 懒汉式: 
*      全局变量初始化放到了实例化方法中,延迟产生对象。 *      但是当多个线程统一访问时,有可能出现线程不安全的情况。需要优化。 * @author 码歌老薛 * @date 创建时间 猴年马月 * @version 1.0 
*/  
public class SingleLazy implements Serializable{  //提供静态的全局变量 作为访问该类实例的入口 但是这里不立即加载  private static SingleLazy sh = null;  /** * 构造器私有 无法创建对象 */  private SingleLazy(){   System.out.println("构造函数被调用了");  }  /** * 对外提供get方法获取 该类的实例 * @return * @throws InterruptedException  */  public static synchronized SingleLazy getInstance() {  if(sh==null){  sh = new SingleLazy();  }  return sh;  }  } 上海尚学堂java培训 shsxt.

 

双重检测

 

/** * 懒汉式: *      全局变量初始化放到了实例化方法中,延迟产生对象。 *      但是当多个线程统一访问时,有可能出现线程不安全的情况。需要优化。 * @author 码歌老薛 * @date 创建时间 猴年马月 * @version 1.0 */  
public class SingleLazy4 {  //提供静态的全局变量 作为访问该类实例的入口 但是这里不立即加载  private volatile  static SingleLazy4 sh = null;  /** * 构造器私有 无法创建对象 */  private SingleLazy4(){  System.out.println("被调用了");  }  /** * 双重校验锁式(也有人把双重校验锁式和懒汉式归为一类)分别在代码锁前后进行判空校验 * ,双重校验锁式是线程安全的。然而,在JDK1.5以前,DCL是不稳定的,有时也可能创建多个实例, * 在1.5以后开始提供volatile关键字修饰变量来达到稳定效果。 * 双重校验锁DCL(double checked locking) * @return * @throws InterruptedException  */  public static SingleLazy4 getInstance() {  if(sh == null){  synchronized(SingleLazy4.class){  if(sh == null){  sh = new SingleLazy4();  //return singleton;    //有人提议在此处进行一次返回  }  //return singleton;    //也有人提议在此处进行一次返回  }  }  return sh;  }  
}  上海尚学堂Java培训 shsxt. 获取更多java学习资料

 

 

静态内部类

 

/** *静态内部类 ** @author 码歌老薛* @date 创建时间 猴年马月 * @version 1.0 */  
public class SingleInner {  /** *静态内部类式和饿汉式一样,同样利用了ClassLoader的机制保证了线程安全; *不同的是,饿汉式在Singleton类被加载时(从代码段3-2的Class.forName可见) *就创建了一个实例对象,而静态内部类即使Singleton类被加载也不会创建单例对象, *除非调用里面的getInstance()方法。因为当Singleton类被加载时 *,其静态内部类SingletonHolder没有被主动使用。只有当调用getInstance方法时, *才会装载SingletonHolder类,从而实例化单例对象。 这样,通过静态内部类的方法就实现了lazy loading,很好地将懒汉式和饿汉式结合起来, 既实现延迟加载,保证系统性能,也能保证线程安全  */  private static class SingleInnerHolder{  private static SingleInner instance = new SingleInner();  }  private SingleInner(){  System.out.println("我被调用了");  }  public static SingleInner getInstance(){  return SingleInnerHolder.instance;  }  
}  

 

枚举单例

 

/** * jvm提供底层保证  * 不可能出现序列化、反射产生对象的漏洞 但是不能做到延迟加载 
在外部,可以通过EnumSingleton.INSTANCE.work()来调用work方法。默认的枚举实例的创建是线程安全的 
、,但是实例内的各种方法则需要程序员来保证线程安全。 
总的来说,使用枚举单例模式,有三个好处: 1.实例的创建线程安全,确保单例。2.防止被反射创建多个实例。3.没有序列化的问题。 * @author 码歌老薛 * @date 创建时间 猴年马月 * @version 1.0 */  
public enum SingleEnum {  //实例化对象  INSTANCE;  /** * 对象需要执行的功能 */  void getInstance(){  }  
}  

反射/序列化 获取对象 以及防止方式

 

import java.io.ObjectStreamException;  
import java.io.Serializable;  /** * 懒汉式: *      全局变量初始化放到了实例化方法中,延迟产生对象。 *      但是当多个线程统一访问时,有可能出现线程不安全的情况。需要优化。 * @author 码歌老薛 * @date 创建时间 猴年马月 * @version 1.0 */  
public class SingleLazy implements Serializable{  //提供静态的全局变量 作为访问该类实例的入口 但是这里不立即加载  private static SingleLazy sh = null;  /** * 构造器私有 无法创建对象 */  private SingleLazy(){  if(sh!=null){  throw new RuntimeException();  }  System.out.println("构造函数被调用了");  }  /** * 对外提供get方法获取 该类的实例 * @return * @throws InterruptedException  */  public static synchronized SingleLazy getInstance() {  if(sh==null){  sh = new SingleLazy();  }  return sh;  }  private Object readResolve()throws ObjectStreamException{  return sh;  }  }  上海尚学堂java培训 shsxt.

3、用法总结:

 

1、懒汉式效率是最低的。
2、占用资源少 不需要延时加载  枚举优于 饿汉式
3、占用资源比较多 需要延时加载 静态内部类 优于  懒汉式

更多Java技术文章欢迎阅读上海尚学堂Java培训,免费试学和线上公开课培训课程等你学习。

更多推荐

模式,完整,Java

本文发布于:2023-06-01 20:42:47,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/430955.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:模式   完整   Java

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!