设计模式-单例模式
设计模式
首先设计模式的研究和应用是以依赖倒转原则为指导原则的,通俗来说设计模式是一套可以反复使用的、为多数人知晓、经过分类编目的、代码设计经验的总结。使用设计模式的目的是为了代码复用,避免程序大量修改,同时使代码易于理解,并且保证代码的可靠性。
设计模式不管是对自己还是对他人都是有用的,引入设计模式的概念,使得程序在编写过程中实现工程化管理。
单例模式(singleton)
单例模式的作用就是保证在整个应用程序的周期中,任何一个时刻,单例类的实例都最多只有一个存在。
使用场景
(1)保证一个类仅有一个实例,而且客户可以从一个周所周知的接口访问它;(2)当这个唯一实例是通过子类化可扩展的类并且客户应该无需更改代码就能使用一个扩展的实例时。
单例模式的七种实现
单例模式确保某一个类只有一个实例,而且自行实例化,并向整个系统提供这个实例单例模式。
单例模式的第一种实现
懒汉模式,线程不安全
public class Singleton{
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(instance ==null){
instance = new Singleton();
}
return instance;
}
}
单例模式的第二种实现
懒汉模式,线程安全
public class Singleton{
private static Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance
}
}
这种写法能够在所线程中很好的工作,而且具备延迟加载的功能,但是效率较低,99%情况下不需要同步。
单例模式的第三种实现
饿汉模式
public class Singleton{
private static singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
这种方式基于classloader机制,避免了多线程的同步问题,不过instance在类装载时就实例化,虽然导致类转载的原因很多种,在单例模式中大多数都是调用getInstance方法。
单例模式的第四种实现
饿汉 变种
public class Singleton{
private Singleton instance = null;
static {
instance = new Singleton();
}
private Singleton(){}
public static Singleton getInstance(){
return this.instance;
}
}
饿汉的变种与其本身差别不大,都是在类初始化即实例化instance
单例模式的第五种实现
静态内部类
public class Singleton{
private static class SingletonHolder{
private static final Singleton INSTSNCE = new Singleton();
}
private Singleton(){}
public static final Singleton getInstance(){
return SingletonHolder.INSTSNCE;
}
}
这种实现方式同样利用率classloader机制来保值初始化instance时只有一个线程,它和饿汉及其变种的不同在于前两种只要Singleton类被装载了,那么instance就会被实例化,也就是没有达到延迟加载的效果,而这种方式是Singleton类被加载了,instance不会被初始化,因为SingletonHolder类没有被主动使用,只有现实调用getInstance方法是才会现实加载SingleHolder类,进而实例化instance。
单例模式的第六种实现
枚举
public class Singleton{
INSTANCE;
public void whateverMethod(){
}
}
这种方式是Effective Java作者Josh Bloch提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象
单例模式的第七种实现
双重校验锁
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;
}
}
sychronized 首先保障初始化为线程安全的,二层if判断避免了多线程同时进入getSingletton()并以相同身份进入等待,volatile解决重排序问题,因为volatile有内存屏蔽的功能。
参考资料:
·https://www.zhihu.com/question/35268028----双重检查锁失效是因为对象的初始化并非原子操作?
·http://ifeve.com/doublecheckedlocking/---有关“双重检查锁定失效”的说明
·https://my.oschina.net/u/866190/blog/205454----正确使用双重检查锁(DCL)