单例模式以及5种实现方式

单例模式:在多线程环境下,对外存在一个对象,并且提供一个访问该实例的全局访问点。

说白了就是给类“计划生育”,对外只能有一个。

应用场景:

 * 常见应用场景:
 * 1.Windows的Task Manager(任务管理器)就是典型的单例模式:启动多次都是一个管理器。
 * 2.Windows的回收站也是单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。
 * 3.项目中。读取配置文件的类,一般也只有一个对象,没有必要每次使用配置文件数据,每次new
 *   一个对象去获取。
 * 4.网站的计数器,一般也是采用单例模式实现,否则难以同步。
 * 5.应用程序的日志应用,一般都用单例模式实现。由于共享的日志文件一直处于打开状态,因为只
 *   能有一个实例去操作,否则内容不好追加。
 * 6.数据库连续池的设计一般也是单例模式,因为数据库连续是一种数据库资源。
 * 7.操作系统的文件系统,也是大的单例模式实现的例子。一个操作系统只能有一个文件系统。
 * 8.Application也是单例(servlet编程中会涉及到)
 * 9.在Spring中,每个Bean默认就是单例的,这样做的优点是Spring容器可以管理
 * 10.在service编程中,每个Service也是单例
 * 11.在Spring MVC框架/struts1框架中,控制器对象也是单例

优点:

* 优点:由于单例模式只生成一个实例,减少了系统性能开销。当一个对象的产生需要比较多的
 *   资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,
 *   然后永久驻留内存的方式来解决。
 *   单例模式可以在系统设置全局的访问点,优化共享资源访问,例如可以设计一个单例类,复责
 *   所有数据表的映射处理

5种实现方式: 

* 常见五种单例模式实现方式:
 *   主要:
 *      饿汉式:线程安全,调用效率高,不能延时家族。
 *      懒汉式:线程安全,调用效率不高,可以延时加载。
 *   其他:
 *      双重检测锁式:由于JVM底层内部模型原因,偶尔会有问题,不建议使用。
 *      静态内部类式:线程安全,调用效率高,可以延时加载。
 *      枚举单例:线程安全,调用效率高,不能延时加载。
 *步骤
 * 1.构造器私有化,避免外部new构造器
 * 2.提供私有的静态属性,存储对象的地址
 * 3.提供公共的静态方法,获取属性

 第一种饿汉式:

public class TestDcl {

  /*
   2. 饿汉式:类初始化时,立即加载这个对象,不能延时
     */
    private static TestDcl instance =new TestDcl();

 //1.构造器私有化
    private TestDcl(){
       
    }
    
   //3.饿汉式:线程安全,不需要同步,效率高
    public static TestDcl getInstance(){
        return instance;
    }

}

 第二种懒汉式

public class TestDcl {
    /*
    2.提供私有的静态属性
    没有volatile其他线程可能访问一个没有初始化的对象,
    因为新建一个对象是要开辟空间,然后初始化对象,最后返回对象的地址给引用,
    如果创建一个对象比较慢,那么会先一步返回地址,还没初始化,那么得到的是一个空的对象。
    volatile保证线程间变量的可见性,也就是变量修改后会马上写到主内存里,然后从主内存拿
    最新的,而不是缓存。
    懒汉式:延时加载,用的时候才加载,不会造成浪费,资源利用率高。
     */
    private static volatile TestDcl instance;
    //1.构造器私有化
    private TestDcl(){

    }
    //3.需要加同步,调用效率低。
    public static synchronized TestDcl getInstance(){
         if (null == instance) {
                instance = new TestDcl();
            }
        return instance;
    }

  
}

第三种双重检测锁式:

public class TestDcl {

  /*
   2.双重检测锁式:结合了饿汉懒汉的优点:提高了执行的效率,
      不必每次获取对象时都进行同步,只有第一次才同步,创建了
      以后就没必要了。
      但由于编译器优化原因和JVM底层内部模型原因,偶尔会出问题,不推荐使用。
     */
    private static TestDcl instance =null;

 //1.构造器私有化
    private TestDcl(){
       
    }
    
   //3.
   public static  TestDcl getInstance(){
        if (null == instance) {
                TestDcl dcl;
              synchronized (TestDcl.class) {
                  dcl =instance;
                  if(dcl ==null){
                      synchronized (TestDcl.class){
                          if(dcl ==null){
                              dcl =new TestDcl();
                          }
                      }
                      instance = dcl;
                  }

              }
        }
        return instance;
   }

}

第四种静态内部类式:

public class TestDcl {

  /*
   2. 静态内部类式:也是一种懒加载方式
     */
    private static class DclClassInstance{
        private static final TestDcl instance = new TestDcl();
    }

 //1.构造器私有化
    private TestDcl(){
       
    }
    
   //3.
    public static TestDcl getInstance(){
        return DclClassInstance.instance;
    }

}

第五种枚举:

enum Dcl{
    //这个枚举元素本身就是单例,由JVM从根本上提供保障,避免通过反射和反序列的漏洞,枚举是最安全的。
    INSTANCE;

    //添加自己需要的操作

}

调用:可以每个模式都试下,对象是一样的。

public static void main(String[] args) {
        Thread thread = new Thread(()->{
            System.out.println(TestDcl.getInstance());
        });
        thread.start();
        System.out.println(TestDcl.getInstance());

        System.out.println(Dcl.INSTANCE ==Dcl.INSTANCE);
    }

结果:

cn.oyh.thread.TestDcl@6d311334
cn.oyh.thread.TestDcl@6d311334
true

怎么选择用哪个模式?

*如何选用?
 *  占用资源少 ,不需要延时加载:枚举式  好于  饿汉式
 *  占用资源大,需要延时加载:静态内部类  好于  懒汉式

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值