博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
第五式 单例模式
阅读量:5307 次
发布时间:2019-06-14

本文共 3448 字,大约阅读时间需要 11 分钟。

单例模式

什么是单例模式

  单例模式:确保一个类只有一个实例,并提供一个全局访问点。

  我们把某个类设计成自己管理的一个单独实例,同时也避免其他类再自行产生实例。同时提供该实例的全局访问点,当你需要实例时,向类查询,会返回单个实例。

 

如何实现

  平时我们需要对象时,都是new一个出来。这次单例设计模式,通过new的方式,每次出来的对象都不是同一个了,不符合单例模式设计原则。new对象是通过

类自身的公开的构造方法,我们可以通过将构造方式私有不让别人调用,然后提供一个静态方法让需要的人来获取该实例对象。根据该实例对象创建时间,可以分为

懒汉式和饿汉式。

  饿汉式:

1 //饿汉式2 public class Single {3     private static Single single = new Single();4     private Single(){}5     public static Single getInstance(){6         return single;7     }8 }

  懒汉式:

1 //懒汉式 2 public class Single { 3     private static Single single; 4     private Single(){} 5     public static Single getInstance(){ 6         if(single == null){ 7             single = new Single(); 8         } 9         return single;10     }11 }

  利弊:饿汉式在程序运行时就创建好了单例对象,这个对象可能会一直用不上,但一开始就被创建了占用资源,造成浪费。懒汉式是有人要用到这个单例对象时才把它创建出来,达到了

资源利用的最合理化,但是他不是线程安全的。看下面的代码就知道了,私有的构造方法被调用了两次,也就是说没有实现输出单例。

1 public class Client { 2     public static void main(String[] args){ 3         for(int i=0;i<2;i++){ 4             //创建两个线程,去获取单例 5             new Thread(){ 6                 public void run(){ 7                     Singleton.getInstance(); 8                 } 9             }.start();10         }11     }12 }13 14 class Singleton {15     private static Singleton singleton;16     private Singleton(){17         System.out.println("我被创建了!");18         try {19             //模拟复杂对象创建时,耗费的时间20             Thread.sleep(1000);21         } catch (InterruptedException e) {22             e.printStackTrace();23         }24     }25     public static Singleton getInstance(){26         if(singleton == null){27             singleton = new Singleton();28         }29         return singleton;30     }31 }32 33 运行结果:34 我被创建了!35 我被创建了!

  如果我们将getInstance方法变成同步方法,就可以避免多线程问题。像下面这样

1     public static synchronized Singleton getInstance(){2         if(singleton == null){3             singleton = new Singleton();4         }5         return singleton;6     }7 8  运行结果:9  我被创建了!

  通过增加synchronized关键字到getInstance()方法中,我们迫使每个线程在进入这个方法之前,要先等别的线程离开该方法,这样就没有两个线程同时进入这个方法了。虽然同步解决了线程安全这个问题,但是同步会降低性能,这又是另外一个问题。实际上只有第一次执行getInstance()方法时,才真正需要同步,一旦实例被创建完毕之后,就不需要同步了。优化一下代码

1 public static Singleton getInstance(){ 2         if(singleton == null){ 3             synchronized (Singleton.class){ 4                 if(singleton == null){ 5                     singleton = new Singleton(); 6                 } 7             } 8         } 9         return singleton;10     }11 12 运行结果:13 我被创建了!

  这方法叫做“双重检查加锁”,在getInstance()中减少使用同步。

 

  静态内部类实现单例模式,可以兼顾线程安全和懒加载。

1 //这种方式,线程安全,调用效率高,并且实现了延迟加载 2 class Singleton { 3     private static class SingletonClassInstance{ 4         private static final Singleton singleton = new Singleton(); 5     } 6     private Singleton(){ 7         System.out.println("我被创建了!"); 8         try { 9             //模拟复杂对象创建时,耗费的时间10             Thread.sleep(1000);11         } catch (InterruptedException e) {12             e.printStackTrace();13         }14     }15     public static Singleton getInstance(){16         return SingletonClassInstance.singleton;17     }18 }
   运行结果:    我被创建了!

   要点:外部类没有static属性,不会像饿汉式那样立即加载对象;只有调用getInstance才会加载静态内部类,而加载类是天然的线程安全的,singleton是static final类型,保证了内存中只有一个实例存在;兼备了并发高效调用和延迟加载的优势。

 

应用场景

  1、Windows的Task Manager(任务管理器)就是典型的单例模式

  2、网站的计数器也是单例,不然不好同步

  3、应用程序的日志应用,一般都使用单例模式,因为共享的日志文件一直处于打卡状态,只能一个实例去操作,否则不好追加

  4、Spring中,每个Bean默认就是单例,这样可以方便被Spring容器管理

  5、spring MVC框架中,控制器对象也是单例

 

转载于:https://www.cnblogs.com/bwyhhx2018/p/10753247.html

你可能感兴趣的文章
ASCII、Unicode和UTF-8等常见字符编码格式介绍
查看>>
英文自动换行的解决方法
查看>>
python-列表解析、字典解析、集合解析
查看>>
作为互联网初创公司,应该具备的条件(一):概述
查看>>
安卓ROOT工具汇总
查看>>
大臣的旅费
查看>>
20180101
查看>>
查看SQL SERVER Job details
查看>>
ts关键还是js 因为要编译成js
查看>>
南阳56
查看>>
基于android studio的快捷开发(将持续更新)
查看>>
《构建之法》阅读笔记03
查看>>
理解多线程中的ManualResetEvent(C#)
查看>>
.Net实现微信公众平台开发接口(二) 之 “获取access_token”
查看>>
Detecting iOS
查看>>
AJAXPro用法
查看>>
[ Git ] [ GitHub ] 如何刪除自己github上面的Repository-轉載
查看>>
微信小程序<每日查看>开发总结
查看>>
asp.net XML转JSON
查看>>
Java 编码规范
查看>>