设计模式之美(1)---单例模式singleton

在这里插入图片描述
一、单例的使用场景:
1)需要频繁的进行创建和销毁的对象
2)创建对象消耗时过多或耗资源过多,但又经常用到的对象
3)工具类对象
4)数据库的连接池也采用单例模式,因为要频繁的访问数据库对象
5)一些共享的配置文件,比如spring的配置文件的读取
6)多线程的线程池的设计也是采用单例模式,由于线程池要方便对池中的线程进行控制
7)网站计数器,一般也是采用单例模式,否则难以实现同步

二、单例的优点:
  1.在单例模式中,活动的单例只有一个实例,对单例类的所有实例化得到的都是相同的一个实例。这样就防止其它对象对自己的实例化,确保所有的对象都访问一个实例
  2.单例模式具有一定的伸缩性,类自己来控制实例化进程,类在实例化进程上有相应的伸缩性
  3.提供了对唯一实例的访问入口
  4.由于在系统内存中只存在一个对象,因此可以节约系统资源,当需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能
  5.允许可变数目的实例(可以根据实际情况需要,在单例模式的基础上扩展做出双例模式、多例模式)
  6.避免对共享资源的多重占用

三、单例的缺点:
  1.不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态
  2.由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。
  3.单例类的职责过重,在一定程度上违背了“单一职责原则”
  4.滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失

  
四、单例的实现
单例模式实现的方式有:懒汉式、饿汉式、双重校验锁、静态内部类、枚举法以及各自的变种方式

推荐使用的实现方式:双重校验锁(基于懒汉式)、静态内部类、枚举法

1.一般写法:懒汉式
以下普通写法,在单线程中没问题,但是如果在多线程中,
当一个线程进入判断语句if(null==singletonOne) 时会发生线程阻塞,
此时第二个线程进来了,创建了一个实例,当阻塞线程被唤醒时,就会又创建一个对象实例,显然与单例模式不符合

问题:单线程下没问题,多线程下存在创建多个实例问题,不采用
package com.creational.singleton;
public class SingletonOne {
 private static SingletonOne singletonOne;
 private SingletonOne() {
 }
 public static SingletonOne getInstance1() {
  if(null==singletonOne) {
   singletonOne = new SingletonOne();
  }
  return singletonOne;
 }
}

2.一般写法:饿汉式
原理:声明一个私有的构造方法,创建一个私有的静态实例,公有的获取实例的方法

问题:如果该对象的构造函数很复杂的话,类加载时就会耗费很多性能,不采用
package com.creational.singleton;
public class SingletonTwo {
 private static SingletonTwo instance = new SingletonTwo();
 public static SingletonTwo getInstance1() {
  return instance;
 }
}

3.多线程下实现:同步锁–基于懒汉式

问题:下面代码还是存在性能问题,因为同步锁机制,多个线程获取类实例对象会排队等待获取锁,这样是没有必要的,因为大多数情况下类实例对象已经创建成功了,所以不用进入加锁代码块
package com.creational.singleton;
public class SingletonOne {
 private static SingletonOne singletonOne;
 public static SingletonOne getInstance2() {
 synchronized (SingletonOne.class) {
  if(null==singletonOne) {
   singletonOne = new SingletonOne();
   }
  }
  return singletonOne;
 }
}

4.多线程下实现:双重校验锁–基于懒汉式
这种写法能够做到效率和安全的双重保证,适用于jdk1.5+
推荐使用

package com.creational.singleton;
public static SingletonOne getInstance3(){
 private static SingletonOne singletonOne;
 private SingletonTwo() {}
 if(null == singletonOne){
  synchronized(SingletonOne.class){
   if(null ==singletonOne){
    singletonOne = new SingletonOne ();
   }
  }
 }
}

5.多线程下实现:静态代码块–基于饿汉式
在静态代码块中去创建实例,其实实现方式跟一般饿汉式差不多,都是在类加载的时候创建实例,没有达到懒加载的机制,不采用

package com.creational.singleton;
public class SingletonTwo {
 private static SingletonTwo instanceEx = null;
 private SingletonTwo() {}
 static {
  instanceEx = new SingletonTwo();
 }
 public static SingletonTwo getInstance2() {
  return instanceEx;
 }
}

6.多线程下实现:静态内部类方法
原理:同样利用了classLoader的机制来保证初始化instance时只有一个线程。比较饿汉式的两种方式,其实看起来差别不大,但是使用静态内部类:当SingletonThree 被装载时,静态内部类SingletonClass并没有被类加载器加载,因此instance实例并没有被初始化,只有当外部调用getInstance()方法时才会去装载静态内部类,此时静态成员变量就会被加载,而且只加载一次,进而达到了懒加载机制,并且实现了单例模式。

推荐使用
package com.creational.singleton;
public class SingletonThree {
 private static class SingletonClass {
  private static SingletonThree instance = new SingletonThree();
 }
 public static SingletonThree getInstance() {
  return SingletonClass.instance;
 }
}

7.多线程下实现:枚举实现

//最简洁、易用的单例实现方式,(《Effective Java》推荐)
package com.designmode;
public enum Singleton{
//定义一个枚举的元素,它就是Singleton的一个实例
INSTANCE;
 private Singleton() {
 }
 public void doSomething(){
 }
}

调用方式:

Singleton.INSTANCE.doSomething();

源码地址 : [https://github.com/lvxiaojun/java-design-patterns]

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值