您的位置:首页 > 编程语言 > Java开发

JAVA设计模式之单例模式

2017-08-29 15:59 204 查看

最近发生的事

  三月底,我辞去了大学毕业后在深圳的第一份工作,回到我的老家——中国最贫穷的直辖市,回来前,差不多犹豫了半年,一方面害怕回来工作不好找,同时加上在那边的一些朋友,最后再三思量还是一咬牙一跺脚,回来了。

回来后,花了几天时间去面试,运气还算可以,基本上都给offer了,然后选了一家公司算是稳定下来了,四月初正式入职。

事实证明,路是自己走出来的,逃离深圳也没有之前想象中那么难,就看你有没有那一份勇气。

到现在,在新公司入职差不多三四个月,适应得差不多了,这一段时间,一直没有写博客,一方面是因为换了工作环境,在努力适应,另一方面是这一段时间自己没有补充新知识,我觉得自己没什么可写的,现在算是重操旧业吧,给自己充一下电。

JAVA设计模式

  Java设计模式其实算是java在发展的过程中前人总结下来的一种经验,针对于不同的应用场景,可以用不同的设计模式来解决问题,同时,在有的场景,可以有多种设计模式可以选择,这就需要我们对设计模式了解得足够透彻,然后才能去找到最适合的设计模式。

以前我也一直在看设计模式,只是一直没有去系统的学习,然后转化为博客笔记,加深自己对设计模式的理解。后面会把这些设计模式系统学习一遍写成博客,当做是自己学习的一种记录。

JAVA设计模式之单例模式

  java的单例模式应该是最简单最容易实现,同时也是面试特别容易遇到的一种设计模式了。顾名思义,单例模式就是我们的某个类在应用中需要以单个实例的方式存在,不管在哪里以及什么时候调用,都是拿的这个实例,而不是去重新初始化。

  单例模式在开发中的应用也是很常见的,比如web应用的配置对象的读取、数据库连接池的设计、windows的任务管理器等等这些。

  虽然单例模式简单,实现所需要的代码数量也不多,但是考虑到懒加载、线程安全等问题,其实也是很容易出问题的,通常面试的时候,如果考到单例模式也是拿这些问题来考量的。

  同时单例模式也有多种实现方式。

饿汉式

public class  Singleton {
private static final Singleton instance = new Singleton();
public Singleton(){

}
public static Singleton getInstance(){
return instance;
}
}


  这种饿汉式的单例模式,因为类第一次加载的时候就初始化了,所以是线程安全的,唯一不足的就是它不是懒加载的方式。

懒汉式

public class  Singleton {
private static Singleton instance = null;
public Singleton(){

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


  这种单例模式既实现了懒加载,也满足了线程安全,看似非常完美了,但是其实它并不高效,因为这种方式加锁在方法上了,因为锁粒度的问题,导致每次进入方法的只会有一个线程,其他线程都会被挡在方法外,等待前一个线程执行完这个方法。仔细想一下,其实是没必要的,我们可以将锁的粒度变得更细,因此也演变出了双重锁验证的实现方式。

双重锁验证

public class  Singleton {
//volatile:1、保证instance的可见性 2、禁止jvm的重排序优化
private static volatile Singleton instance = null;
public Singleton(){

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


  这种方式实现单例模式是最容易在面试中被提到的,这里有两次判空操作,因此叫双重锁验证,为什么这里需要double check,当我们想不通的时候,其实可以试试反证法,这里如果第一次验证不要的话,可以发现,就和懒汉式其实是一样的了,那么这样就会造成不高效,那为什么需要第二次的验证呢,可以想想,如果取消第二次的验证,可能会有多个线程进入if语句,然后单独进入同步块,这样就会造成多个实例,因此两次验证缺一不可。

  这里需要注意的是volitile这个关键字,为什么要在instance加这个关键字,这个关键字有两个作用,一个是保证instance的内存可见性,也就是每次读写操作都保证是内存中的最新值,另一方面是禁止jvm的重排序优化,如果这里不加这个关键字,由于jvm的重排序优化,可能会导致instance还没有初始化完成,其他线程就得到了这个instance的引用值,然后就顺理成章的报错。详情可以去看周老先生的《深入java虚拟机》

内部静态类

public class  Singleton {
public Singleton(){

}
private static class SingletonHolder{
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance(){
return SingletonHolder.INSTANCE;
}
}


  内部静态类的方式来实现是我比较喜欢的方式了,因为这种方式满足懒加载,没有线程安全问题,同时也十分高效,光看代码也容易让人理解。

枚举类

public enum Singleton {

INSTANCE;
}


  这种方式应该是实现单例模式最简洁的方式了,调用直接用Singleton.INSTANCE就可以了。

更多链接

Double Checked Locking on Singleton Class in Java

如何正确地写出单例模式

Simplest way to impelment Singleton pattern in Java - Example

20 Design pattern and Software design interview questions for Programmers
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息