单例模式

单例

  1.饿汉式单例

    优点:没有加锁,执行效率更高

         缺点:类加载的时候就初始化,不管用否都占着空间,如果项目中存在大量的单例对象,则会浪费内存空间

    

 

 

 

  2.懒汉式单例

    优点:被外部类调用时,内部才会加载

    

 

 

      存在线程安全,当有多个线程同时访问时,返回多个实例,违反了单例对象原则

    

 

 

     添加了synchronized关键字,当有大量线程同时访问时,cpu分配压力上升,造成阻塞,造成性能下降

    

 

     双重检查锁 

    这里的写法将同步放在了方法里面的第一个非空判断之后,这样可以确保对象不为空的时候不会被阻塞,但是第二个非空判断的意义是什么呢?我们假设线程A首先获得锁,进入了第3行,还没有释放锁的时候,线程B又进来了,这时候因为线程还没有执行对象初    始化,所以判空成立,会进入第2行等待获得锁,这时候当线程A释放锁之后,线程B会进入到第3行,这时候因为第二个判空判断对象不为空了,所以就会直接返回,如果没有第2个判空,这时候就会产生新的对象了,所以需要两次判空!

大家可能注意到这里的变量定义上加了volatile关键字,为什么呢?这是因为DCL在可能会存在失效的情况:
第4行代码:lazySingleton = new LazyDoubleCheckSingleton();
大致存在以下三步:
(1)、分配内存给对象
(2)、初始化对象
(3)、将初始化好的对象和内存地址建立关联(赋值)
而这3步由于CPU指令重排序,不能保证一定按顺序执行,假如线程A正在执行new的操作,第1步和第3步都执行完了,但是第2步还没执行完,这时候线程B进入到方法中的第1行代码,判空不成立,所以直接返回了对象,而这时候对象并没有初始化完全,所以就会报错了,解决这个问题的办法就是使用volatile关键字,禁止指令重排序(jdk1.5之后),保证按顺序执行上面的三个步骤

    

 

 

     使用了内部类的特性,LazyHolder里面的内容等到外面调用时才执行,可以被反射或者序列化破坏单例

    

 

    

     

 

 

 

 

 

 

  3.注册式单例

    注册式单例是将所有的对象保存到某一个地方,通过唯一的标识符获取对应的单例对象

    

 

     

 

 

       4.ThreadLacal式单例

    ThreadLacal不能保证创建对象的全局唯一性,但是可以保证单个线程中对象的唯一性

    

 

     

 

posted @ 2021-12-13 17:50  习惯有迩  阅读(34)  评论(0编辑  收藏  举报