单例设计模式

什么是单例模式

单例模式:可以说是23种设计模式种最简单的模式了,是说类只有一个供全局访问的单个实例,类不能实例化。
这里有两个点:

  1. 类只有一个供全局访问的实例
  2. 类不能实例化

为什么使用单例模式

我们期望只提供类的实例供外部系统使用,节约内存。

注意事项:
单例类应该只提供读功能,不提供写功能,也就是说不提供相关的方法改变类实例的状态。
比如:

public class Singleton {  
    private static Singleton instance = new Singleton();  
    private int state
    private Singleton (){}  
    public static Singleton getInstance() {  
    	return instance;  
    }  
    //使用的地方都可能改变状态,导致内部错乱,不建议使用。改为非单例模式更好。
    public void setState(int state) {
    	this.state = state
    }
}

如何使用单例模式

  1. 我们需要因此构造方法,不让外部构造对象。
  2. 我们需要提供静态的接口供外部获取单例类的对象。
  3. 类内部实例化对象

所有的单例模式基本是上面的套路,唯一不同的是类内部实例化对象的过程。

懒汉式 推荐使用

懒汉式是在加载类的class文件时候,直接创建对象,没有使用懒加载,而且是线程安全的。大部分情况下我们都会调用getInstance()方法,而有时不调用的使用,会浪费资源。

public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (){}  
    public static Singleton getInstance() {  
    	return instance;  
    }  
}

饿汉式 推荐使用

饿汉式是说创建对象的过程中使用懒加载,只有真正调用getInstance()时候才进行对象的创建。而饿汉式又分为线程安全的和线程不安全的,只是getInstace方法上是否通过synchronized加锁,这里强烈推荐直接加锁,因为这样可以避免单例类扩展为多线程运行,而我们又忘记枷锁的情况。

public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
    public static synchronized Singleton getInstance() {  
	    if (instance == null) {  
	        instance = new Singleton();  
	    }  
	    return instance;  
    }  
}

双重校验锁 不推荐使用

双重校验锁(DCL,即 double-checked locking)即为在创建对象的过程中添加两次校验,一次是不加锁的校验,一次是加锁的校验。在getInstace需要高并发的使用才会使用,不推荐使用,因为实现起来过于复杂。
这里实现使用注意sychronized和volatile,二者缺一不可

  • sychronized保证原子性
  • volatile保证有序性
public class Singleton {  
   private volatile static Singleton singleton;  
   private Singleton (){}  
   public static Singleton getSingleton() {  
       if (singleton == null) {  
           synchronized (Singleton.class) {  
   	        if (singleton == null) {  
   	            singleton = new Singleton();  
   	        }  
           }  
       }  
 	   return singleton;  
   }  
}

静态内部类 强烈推荐

此方法是通过classloader来保证单例,而且是懒加载。classloader先加载Singleton类,在调用的getInstance()时候才会去加载SingletonHolder类,从而实现懒加载。强烈推荐使用此方式。

public class Singleton {  
    private Singleton (){}  

    private static class SingletonHolder {  
    	private static final Singleton INSTANCE = new Singleton();  
    } 

    public static final Singleton getInstance() {  
    	return SingletonHolder.INSTANCE;  
    }  
}

枚举 强烈推荐

public enum Singleton {  
    INSTANCE;  
}

单例模式优缺点

优点:

  • 提供统一的全局访问的接口,方便调用,而且支持多线程,保护资源
  • 只提供一个类的对象,节约内存

缺点:

  • 不适用于内部状态变化的类
  • 扩展性差,万一后面扩展为非单例的类,能改死人。

Java中单例的原理

对于任意一个类,都必须由加载它的类加载器和这个类本身一起共同确立其在Java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。这句话可以表达得更通俗一些:比较两个类是否“相等”,只有在这两个类是由同一个类加载器加载的前提下才有意义,否则,即使这两个类来源于同一个Class文件,被同一个Java虚拟机加载,只要加载它们的类加载器不同,那这两个类就必定不相等。-《深入理解Java虚拟机》

所以单例是保证同一个classloader加载同一份Class文件,并且创建唯一的对象,使用不同的classloader加载同一个Class文件,不会是单例的。这也是为什么多进程会导致单例失效的原因。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值