java 设计模式 学习笔记(16) 单例模式

单例模式:保证一个类仅有一个实例,并提供一个访问其实例的一个全局访问点

 

根据单例模式的定义,写一个单例模式的例子需要注意两点:

1.实例有该类自己生成 

    为了防止客户代码通过 new Singleton()来实例一个对象,需要将 Singleton的默认构造函数定义为private

2. 提供一个访问其实例的全局访问点

    将访问方法getInstance()定义为 static ,则直接通过Singleton.getInstance() 来获取到实例

3.单例只能有一个实例

   在Singleton类中,将instance 定义为 static ,则保证了不管多少个 Singleton都只有并仅有一个instance 静态变量。

 

单例的实现有两种方式:

饿汉单例:在类被加载时就初始化实例

 

 

懒汉单例:类加载之后,第一次调用getInstance()方法时,才初始化实例。

              不过懒汉式单例的getInstance () 方法需要注意到线程的同步问题:在单例类已经被加载进来,但还没有被调用生成实例之前,有多个线程同时调用getInstance() 方法,那么则可能多次调用  instance = new Singelton_lazy()语句,导致出现多个实例的结果。

所以懒汉单例的getInstance() 方法要使用synchronized 来保证其线程安全性。

 

 

 

 

 

 

现在我们来模拟懒汉单例模式的getInstance() 如果不注意线程安全性时出现的线程不安全现象:

现在将Singleton_lazy 改变一下:  1. 去掉synchronized

                                                  2. 认为的改变getInstance() 方法,但传入的参数为0时,则访问SingletonFull的线程需要休眠500毫秒, 当500毫秒一过,则返回一个单例的实例

 

 

 现在编写两个线程类:

 

 

 

编写测试用的代码:

 

 

输出结果:

 

从输出结果中,我们可以看到Mythread 和 Mythread2 两个线程先后访问getInstance()方法,Mythread 在访问getInstance ()时,因为带了参数 0, 所以getInstance()在还没有建立单例实例时停顿了500毫秒。而在这短时间里,Mythread2 趁虚而入,访问 getInstance()方法,立马生成一个单例实例,并返回给Mythread2 。之后500毫秒过了,Mythread所访问的getInstance 线程苏醒,继而执行 instance  = new SingletonFull() 方法,返回另外一个单例实例。

 

 

那么换个思路,我是否可以将测试用的代码换成:

 

 SingletonFull sFull = SingletonFull.getInstance(0);
  SingletonFull sFull2 = SingletonFull.getInstance(1);
  System.out.println(sFull);
  System.out.println(sFull2);

 

结果显示只生成了一个单例实例,为什么呢?

前面提到了在SingletonFull 中的 Thread.currentThread.sleep(500),是使访问Singleton 类的线程休眠,而不是让SingletonFull 休眠,而且SingletonFull  不是线程类,无法休眠。

 

通过将getInstance() 修改成下面的代码,仅仅是添加了一个输出当前访问SingletonFull 类的线程名字。

 

接着改变测试代码,也添加了一条输出当前线程名称的代码

 

 

最后结果输出:

从结果中可以看到在整个测试代码运行过程中,只有main 线程在运行。并且这里,由于main线程先休眠了500毫秒,然后才依次打印出单例实例的名称。而在前面的测试代码中,程序一执行,就先输出了一个单例实例名称,过了500毫秒后,才输出另外一个单例实例名称。

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值