今天向大家介绍一个相对简单的模式——单例模式。在很多场合中都需要使用单例模式来避免不一致状态,避免政出多头。
JAVA设计模式
Java设计模式其实算是java在发展的过程中前人总结下来的一种经验,针对于不同的应用场景,可以用不同的设计模式来解决问题,同时,在有的场景,可以有多种设计模式可以选择,这就需要我们对设计模式了解得足够透彻,然后才能去找到最适合的设计模式。
以前我也一直在看设计模式,只是一直没有去系统的学习,然后转化为博客笔记,加深自己对设计模式的理解。后面会把这些设计模式系统学习一遍写成博客,当做是自己学习的一种记录。
JAVA设计模式之单例模式
java的单例模式应该是最简单最容易实现,同时也是面试特别容易遇到的一种设计模式了。顾名思义,单例模式就是我们的某个类在应用中需要以单个实例的方式存在,不管在哪里以及什么时候调用,都是拿的这个实例,而不是去重新初始化。
单例模式在开发中的应用也是很常见的,比如web应用的配置对象的读取、数据库连接池的设计、windows的任务管理器等等这些。
虽然单例模式简单,实现所需要的代码数量也不多,但是考虑到懒加载、线程安全等问题,其实也是很容易出问题的,通常面试的时候,如果考到单例模式也是拿这些问题来考量的。
同时单例模式也有多种实现方式。
饿汉式
懒汉式
这种单例模式既实现了懒加载,也满足了线程安全,看似非常完美了,但是其实它并不高效,因为这种方式加锁在方法上了,因为锁粒度的问题,导致每次进入方法的只会有一个线程,其他线程都会被挡在方法外,等待前一个线程执行完这个方法。仔细想一下,其实是没必要的,我们可以将锁的粒度变得更细,因此也演变出了双重锁验证的实现方式。
双重锁验证
这种方式实现单例模式是最容易在面试中被提到的,这里有两次判空操作,因此叫双重锁验证,为什么这里需要double check,当我们想不通的时候,其实可以试试反证法,这里如果第一次验证不要的话,可以发现,就和懒汉式其实是一样的了,那么这样就会造成不高效,那为什么需要第二次的验证呢,可以想想,如果取消第二次的验证,可能会有多个线程进入if语句,然后单独进入同步块,这样就会造成多个实例,因此两次验证缺一不可。
这里需要注意的是volitile这个关键字,为什么要在instance加这个关键字,这个关键字有两个作用,一个是保证instance的内存可见性,也就是每次读写操作都保证是内存中的最新值,另一方面是禁止jvm的重排序优化,如果这里不加这个关键字,由于jvm的重排序优化,可能会导致instance还没有初始化完成,其他线程就得到了这个instance的引用值,然后就顺理成章的报错。详情可以去看周老先生的《深入java虚拟机》
内部静态类
内部静态类的方式来实现是我比较喜欢的方式了,因为这种方式满足懒加载,没有线程安全问题,同时也十分高效,光看代码也容易让人理解。
对于正在学习Java但不知道学习路线,不知道学习方法,不知道该如何找到工作的朋友,我还是要推荐下我自己建的Java学习群:479121291,首先你要是学Java的,其次不管你是小白还是大牛,小编都挺欢迎,群里每天都会分享Java相关干货,包括我最近整理出的一份适合2018年自学的最新Java资料,都送给大家,欢迎初学和进阶中的小伙伴。
枚举类
这种方式应该是实现单例模式最简洁的方式了,调用直接用Singleton.INSTANCE就可以了。