设计模式:创建型单例模式
Posted JavaLog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式:创建型单例模式相关的知识,希望对你有一定的参考价值。
因为最近本人也在学习设计模式,就在此记录一下学习过程算是分享一下吧
设计模式在维基百科中是这样定义的,意指软件设计中普遍存在问题的解决方案。这个术语是由埃里希·伽玛(Erich Gamma)等人在1990年代从建筑设计领域引入到计算机科学的。
概念
单例模式属于创建型模式的一种,单例对象的类保证只有一个实例存在。
在我们的系统中,许多时候只需要一个全局的对象实例,这样有利用不重复创建对象,协调系统整体的行为。
比如,在某个服务器程序中,该服务器的配置文件只保存一份,这些保存的数据有一个全局的单例对象读取,同样,也简化了在复杂环境下的配置管理。
全局日志管理,以前的系统中创建全局日志对象,现在日志对象使用单例的就可以解决日志冲突等问题
全局配置管理,当前服务器配置文件使用一个全局的单例对象读取
系统中全局的id生成器,所有生成id的地方全使用这个单例类,保证id唯一
创建单例模式,我们的关注点无非其实就是下面几个
构造函数是私有的,防止外部通过new 创建
考虑创建对象时的线程安全问题
考虑是否支持延迟加载
考虑getInstance()性能是否高
一、饿汉式(全局的单例实例在累加载时创建)
public class HungryIdGenerator {
private AtomicLong id = new AtomicLong(0);
private static final HungryIdGenerator instance = new HungryIdGenerator();
private HungryIdGenerator() {
}
public static HungryIdGenerator getInstance(){
return instance;
}
public Long getId(){
return id.incrementAndGet();
}
}
public class SingleApplicationTests {
public void HungryIdGeneratorTest() {
HungryIdGenerator instance = HungryIdGenerator.getInstance();
System.out.println(instance.getId());// 输出1
HungryIdGenerator i1 = HungryIdGenerator.getInstance();
System.out.println(i1.getId()); // 输出2
}
}
分析: 饿汉式单例是比较简单的,在类加载时,instance实例就已经创建初始化完成,所以instance实例的创建过程是线程安全的。这种方式不支持懒加载,即使用到时在加载
二、懒汉式单例
public class LazyIdGenerator {
private AtomicLong id = new AtomicLong(0);
private static LazyIdGenerator instance ;
private LazyIdGenerator() {
}
public static synchronized LazyIdGenerator getInstance(){
if(null == instance){
instance = new LazyIdGenerator();
}
return instance;
}
public Long getId(){
return id.incrementAndGet();
}
}
public void LazyIdGeneratorTest() {
LazyIdGenerator instance = LazyIdGenerator.getInstance();
System.out.println(instance.getId());// 输出1
LazyIdGenerator i1 = LazyIdGenerator.getInstance();
System.out.println(i1.getId()); // 输出2
}
分析:懒汉式也就是字面意思,比较懒,什么时候用到什么时候加载。因为不加锁并发场景下可能会出现获取到两个实例到情况,所以我们加了一把大锁,所以并发度就大大降低了 。如果这个单例偶尔用到还可以接受,如果频繁用到,那频繁的加锁,解锁并发度就大大的降低了,造成性能瓶颈
三、双重检测单例
public class DoubleCheckIdGenerator {
private AtomicLong id = new AtomicLong(0);
private static DoubleCheckIdGenerator instance ;
private DoubleCheckIdGenerator() {
}
public static DoubleCheckIdGenerator getInstance() {
if (instance == null) {
synchronized(DoubleCheckIdGenerator.class) {
if (instance == null) {
instance = new DoubleCheckIdGenerator();
}
}
}
return instance;
}
public long getId() {
return id.incrementAndGet();
}
}
public void doubleCheckIdGeneratorTest() {
DoubleCheckIdGenerator instance = DoubleCheckIdGenerator.getInstance();
System.out.println(instance.getId());
DoubleCheckIdGenerator i1 = DoubleCheckIdGenerator.getInstance();
System.out.println(i1.getId());
}
分析:饿汉式不支持延迟加载,懒汉式有并发性能问题,双重检查支持拦截在和支持高并发的单例,只要是创建了实例,就不会在进入加锁的逻辑。针对指令重排序问题,造成实例被new出新的实例问题在新版本中不会重现已经被jdk优化,只有低版本才出现因为重排造成的非单例对象创建
四、静态内部类
public class InnerIdGenerator {
private AtomicLong id = new AtomicLong(0);
private InnerIdGenerator() {
}
private static class InnerIdGeneratorHolder{
private static final InnerIdGenerator instance = new InnerIdGenerator();
}
public static InnerIdGenerator getInstance(){
return InnerIdGeneratorHolder.instance;
}
public Long getId(){
return id.incrementAndGet();
}
}
public void innerIdGeneratorTest() {
InnerIdGenerator instance = InnerIdGenerator.getInstance();
System.out.println(instance.getId());
InnerIdGenerator i1 = InnerIdGenerator.getInstance();
System.out.println(i1.getId());
}
分析:使用java的静态内部类创建单例,当外部类加载时不会创建,只有当调用getInstance方法时InnerIdGeneratorHolder才会触发加载,instance的唯一性,创建过程的安全性都有jvm保证,所以这种方式既实现类延迟加载又实现了线程安全
五、枚举单例模式
public enum IdGeneratorEnum {
/**
* 单例对象
*/
INSTANCE;
private AtomicLong id = new AtomicLong(0);
public Long getId(){
return id.incrementAndGet();
}
}
@Test
public void enumIdGeneratorTest() {
IdGeneratorEnum instance = IdGeneratorEnum.INSTANCE;
System.out.println(instance.getId());
IdGeneratorEnum i1 = IdGeneratorEnum.INSTANCE;
System.out.println(i1.getId());
}
分析:利用java枚举类自身的特点来实现单例,最简单实现单例的一种方式,保证了线程安全和实例的唯一
饿汉式:类加载时就已经把instance创建好,所以实例的创建是线程安全的,但是不支持延迟加载
懒汉式:相对于饿汉式是支持懒加载,这种会导致频繁的加锁,解锁,导致并发度低,造成性能瓶颈
个人推荐如果必须使用单例,就使用枚举,最简单,最安全
源码在github
https://github.com/TianPuJun/tz_design_pattern.git
以上是关于设计模式:创建型单例模式的主要内容,如果未能解决你的问题,请参考以下文章