单例模式是在平时的项目开发中比较常见的一种设计模式,使用比较普遍,网上的资料也是一抓一大把,小Alan也来凑凑热闹,为以后充实点设计模式相关的内容做个简单的开篇。

单例模式是一种创建对象的模式,用于产生这个类的一个具体的实例对象,跟普通的对象创建比起来就那么一点点区别,区别就在于它可以确保项目中的一个类只会产生一个具体的对象实例。而不会出现第二个对象实例,第三个对象实例。所有使用到这个对象实例的地方实际上用的都是同一个对象,这就是所谓的单例模式,对于初学者还可能陌生,对于老司机们来讲这可是最最简单的设计模式之一。

在Java中使用单例模式有哪些好处嘞?

①对于频繁使用、经常使用的对象,可以省略创建对象也就是没对象的需要new一个对象所花费的时间,这对于那些重量级的对象来说,还是能少来一个就少来一个,用老对象就好了,减少开销;

②创建对象的次数变少了,对系统内存使用的频率就会降低,这样就减轻了GC的压力,缩短了GC所耗费的时间;

③开发项目的过程中遇到类只需要一个对象实例的时候,那么就是选择这模式无疑了。

单例的实现1:

下面给出一个单例的实现,这个实现是so easy的,代码如下:

 /**
  * 单例模式
  * @author AlanLee
  *
  */
 public class Singleton
 {

     // 饿汉模式
     private static Singleton instance = new Singleton();

     private Singleton()
     {
         System.out.println("Singleton is create");
     }

     public static Singleton getInstance()
     {
         return instance;
     }

 }

使用这种方式创建单例对象有几点需要特别注意。

第一点:我们要保证我们的项目中不会有人意外的创建多余的对象实例的话,我们需要把Singleton的构造函数设置为private私有的。这样其他开发人员就不能随便的创建这个类的对象实例了,从而避免该类的对象实例被错误的创建出来;

第二点:instance对象必须是private私有的并且static静态化的。如果不是private私有的,那么instance的安全性无法得到保证。一不小心可能就被其他开发人员来个Singleton.instance=xxx的,那这个对象也就被改变了,如果=null的话,可想而知,在使用这个对象实例的使用,迎接你的将是空对象异常的怀抱。其次,因为工厂方法getInstance()是static静态方法,因此方法中返回的变量也得是static的。

探讨:每种实现方式在高并发环境下性能如何呢,每种实现方式有木有什么不足之处?

这个单例模式的实现方式性能是非常好的,因为工厂方法getInstance()只是简单的返回instance对象实例,并没有任何锁操作,因此在并行程序中,还是会有比较不错的表现滴。

但是这种方式有一点不足,就是instance对象实例在什么时候被创建出来是不受控制的,基础好点的都知道static成员会在类第一次初始化的时候被创建,这个时候可不一定是工厂方法getInstance()第一次被调用的时候。

假设你的单例模式是这样的,代码如下:

 /**
  * 单例模式:实例对象第一次初始化的问题
  *
  * @author AlanLee
  *
  */
 public class Singleton2
 {
     public static int STATUS = 1;

     private static Singleton2 instance = new Singleton2();

     private Singleton2()
     {
         System.out.println("Singleton2 is create");
     }

     public static Singleton2 getInstance()
     {
         return instance;
     }

 }

注意,这个单例还包含另一个静态成员STATUS。此时,在任何地方引用这个STATUS都会导致instance对象实例被创建(任何对Singleton2方法或者字段的引用,都会导致类初始化,并创建instance实例,但是类初始化只有一次,因此instance实例永远只会被创建一次)。

比如:System.out.println(Singleton.STATUS);

上述println会打印出:

可以看到,就算我们没有要求创建instance单例对象,new Singleton2()也会被调用。

如果不在乎这个小小的不足之处,这种单例模式的实现方式是一种不错的选择。它容易实现,代码易读而且性能优越。

单例的实现2:

如果你想精准的控制instance的创建时间,那么就需要使用下面这种方式,一种支持延迟加载的策略,它只会在instance被第一次使用时才会创建对象。代码如下:

 /**
  * 单例模式之懒汉模式
  *
  * @author AlanLee
  *
  */
 public class LazySingleton
 {
     private static LazySingleton instance = null;

     private LazySingleton()
     {
         System.out.println("LazySingleton is create");
     }

     public static synchronized LazySingleton getInstance()
     {
         if (instance == null)
         {
             instance = new LazySingleton();
         }
         return instance;
     }
 }

最初我们并不需要实例化instance对象实例,只有工厂方法getInstance()被第一次调用时才会创建单例对象。但是在高并发环境下,为了防止对象被对此创建,我们不得不使用synchronized进行方法同步。这种实现的好处是,充分利用了延迟加载,只有在真正需要时才创建对象。但坏处也很明显,并发环境下加锁,在锁竞争激烈的时候会对性能产生一定的影响。

此外,还有一种被称为双重检查模式的方法可以用于创建单例。这是一种非常丑陋、复杂的方法,甚至在低版本的JDK中都不能保证正确性。不推荐使用,也没必要在这种方法上花费太多时间。

单例的实现3:

在上述的单例模式实现方式中,可说是各有千秋,那么第三种方式便是结合两者的优势的一种两全其美的实现方式,代码如下:

 /**
  * 无懈可击之单例模式
  *
  * @author Alanlee
  *
  */
 public class StaticSingleton
 {

     private StaticSingleton()
     {
         System.out.println("StaticSingleton is create");
     }

     private static class SingletonHolder
     {
         private static StaticSingleton instance = new StaticSingleton();
     }

     public static StaticSingleton getInstance()
     {
         return SingletonHolder.instance;
     }

 }

上述代码实现了一个单例模式,并且同时拥有前两种方式的优点。首先工厂方法getInstance()没有使用同步锁,这使得在高并发环境下性能得到了提升。其次,只有在工厂方法getInstance()被第一次调用时,StaticSingleton的实例才会被创建。这种方式巧妙地使用了内部类和类的初始化方式。内部类SingletonHolder被申明为private私有的,这使得我们不可能在外部访问并初始化它。而我们只能在工厂方法getInstance()内部对SingletonHolder类进行初始化,利用虚拟机的类初始化机制创建单例对象。

结束语:宠辱不惊,闲看庭前花开花落;去留无意,漫随天外云卷云舒......小Alan除了喜欢看技术书籍,还是一个武侠玄幻小说爱好者呢!希望自己在IT的这条道路上就能像小说中的主人公一样,纵然困难重重,亦能化险为夷成就康庄大道,至于坐拥美女环抱啥的,小Alan可不想啊,还是有一个深爱的女人足以。

可爱博主:AlanLee

博客地址:http://www.cnblogs.com/AlanLee

本文出自博客园,欢迎大家加入博客园。

Java设计模式探讨之单例模式的更多相关文章

  1. Java设计模式之《单例模式》及应用场景

    摘要: 原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6510196.html 所谓单例,指的就是单实例,有且仅有一个类实例,这个单例不应该 ...

  2. Java设计模式之【单例模式】

    Java设计模式之[单例模式] 何为单例 在应用的生存周期中,一个类的实例有且仅有一个 当在一些业务中需要规定某个类的实例有且仅有一个时,就可以用单例模式 比如spring容器默认初始化的实例就是单例 ...

  3. Java设计模式中的单例模式

    有时候在实际项目的开发中,我们会碰到这样一种情况,该类只允许存在一个实例化的对象,不允许存在一个以上的实例化对象,我们将这种情况称为Java设计模式中的单例模式.设计单例模式主要采用了Java的pri ...

  4. 重学 Java 设计模式:实战单例模式

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 5个创建型模式的最后一个 在设计模式中按照不同的处理方式共包含三大类:创建型模式.结 ...

  5. Java设计模式4:单例模式

    前言 非常重要,单例模式是各个Java项目中必不可少的一种设计模式.本文的关注点将重点放在单例模式的写法以及每种写法的线程安全性上.所谓"线程安全性"的意思就是保证在创建单例对象的 ...

  6. 10.Java设计模式 工厂模式,单例模式

    Java 之工厂方法和抽象工厂模式 1. 概念 工厂方法:一抽象产品类派生出多个具体产品类:一抽象工厂类派生出多个具体工厂类:每个具体工厂类只能创建一个具体产品类的实例. 即定义一个创建对象的接口(即 ...

  7. Java设计模式学习01——单例模式(转)

    原地址:http://blog.csdn.net/xu__cg/article/details/70182988 Java单例模式是一种常见且较为简单的设计模式.单例模式,顾名思义一个类仅能有一个实例 ...

  8. 【java设计模式】-04单例模式

    单例模式 定义: 确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 类型: 创建类模式 类图: 单例模式特点 1.单例类只能有一个实例. 2.单例类必须自己创建自己的唯一实例. 3.单 ...

  9. Java设计模式09:单例模式的强化(控制实例个数n)

    1. 单例模式的本质: 控制实例数目(目的节约资源) 2. 单例模式体现的一些思想: (1)延迟装载(Lazy Load):懒汉式 (2)缓存:饿汉式 3. 单例模式的变形使用: 控制使用实例个数为3 ...

随机推荐

  1. MyBatis学习(六)MyBatis关联映射之一对多映射

    数据库中一对多通常使用主外键关联,外键应该在多方,即多方维护关系. 下面举一个简单实例来看看MyBatis怎么处理一对多的关系. 1.创建一个项目,导入所需jar包,导入db.properties配置 ...

  2. PHP多进程编程pcntl_fork解

    其实PHP是支持并发的,只是平时很少使用而已.平时使用最多的应该是使用PHP-FMP调度php进程了吧. 但是,PHP的使用并不局限于做Web,我们完全也可以使用PHP来进行系统工具类的编程,做监控或 ...

  3. iOS开发-AFNetworking参数和多文件同时上传【多文件上传】

    1. 前言 在项目开发中,我们经常需要上传文件,例如:上传图片,上传各种文件,而有时也需要将参数和多个文件一起上传,不知道大家的项目中遇到了没有,我在最近的项目中,就需要这样的一个功能:同时上传参数. ...

  4. AngularJS–service(服务)

    点击查看AngularJS系列目录 转载请注明出处:http://www.cnblogs.com/leosx/ 服务 Angular的服务也是使用依赖注入(dependency injection ( ...

  5. 五年 Web 开发者 star 的 github 整理说明

    欢迎大家前往腾讯云技术社区,获取更多腾讯海量技术实践干货哦~ 作者:樊东东 前端从业几年,积累了不少github开源库. 有时候想查阅以前star的库,但不好找,github大多库都是英文说明,对中文 ...

  6. CentOS 引导 Win10 启动项

    因为无聊,所以想尝试一下双系统,所以在win10的基础之上,装了一个Linux系统,之前装过Ubuntu,几乎都是自动完成的无任何压力.但是想着Ubuntu好像更新换代有点快,所以换了个能用比较久的C ...

  7. unset与unlink

    unset() -- 释放给定的变量 详见->http://www.kuqin.com/php5_doc/function.unset.html unlink() --删除文件    常用于用户 ...

  8. bzoj3224 普通平衡树(c++vector)

    Tyvj 1728 普通平衡树 2014年8月23日6,4365 Description 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有 ...

  9. Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals)

    http://codeforces.com/contest/831 A. Unimodal Array time limit per test 1 second memory limit per te ...

  10. Ubuntu16.04下安装redis

    Ubuntu16.04下安装redis 保证网络畅通,选定好下载工作路径,执行以下命令下载redis-3.2.6: sudo wget http://download.redis.io/release ...