设计模式系列(六)单例模式的五种实现

参考:

https://design-patterns.readthedocs.io/zh_CN/latest/creational_patterns/singleton.html

对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。

单例模式可以使整个系统拥有一个全局的对象,方便资源的共享和系统行为的协调。

一:饿汉式

public class Singleton {   
    private static Singleton = new Singleton();
    private Singleton() {}
    public static getSignleton(){
        return singleton;
    }
}

饿汉式是最简单的,在类加载的时候就被创建,也没有多线程的问题,

但是不能满足延迟加载的需求

 

二:懒汉式:

public class Singleton {
	//私有静态实例
	private static Singleton  singleton;
	//构造私有
	private Singleton() {}
	public void doSomeThing() {
	        System.out.println("doSomeThing");
	}
	
	 //加锁
    public static synchronized Singleton getInstance() {
        if (singleton == null) {
        	singleton = new Singleton();
        }
        return singleton;
    }

}

懒汉式在用的的时候才考虑第一次创建对象,但是这里会有多线程的问题,多以用synchronized给方法加锁,

但是这里每次访问的时候都是synchronized的,性能会有影响,所以有了第三种

 

三:双重检查锁锁(double checked locking)

public class Singleton {
	//私有静态实例
	private static volatile Singleton  singleton;
	//构造私有
	private Singleton() {}
	public void doSomeThing() {
	        System.out.println("doSomeThing");
	}
	
	 //加锁
    public static  Singleton getInstance() {
        if (singleton == null) {
        	synchronized (Singleton.class){
        		if (singleton==null) {
        			singleton = new Singleton();
				}
        	}
        }
        return singleton;
    }

}

这里面解释一下:

1.为什么synchronized内部就还要再检查一次

因为在一个线程进入synchronized内部的时候,另外一个可能进了第一层if了,所以在锁起来的代码内部还要再判断一次

2.为什么要用volatile修饰singleton

volatile关键字可以保证有序性,如果不加这个关键字的话,可能一个线程在synchronized内部new 但还没执行完,另外一个线程得到的实例虽然不为null,但是并没有初始化

singleton = new Singleton()  这条命令执行分为三部分

1.为对象分配内存

2.执行构造方法语句,初始化实例对象

3.把singleton的引用指向分配的内存空间

如果指令重拍为132,则多线程情况下就会有问题!

-------------------------------------------------------------------------------------------------------------------------

上面三种方式是传统的单例模式实现方式

四:静态内部类

public class Singleton {
	private Singleton() {}
	public void doSomeThing() {
	        System.out.println("doSomeThing");
	}
    public static  Singleton getInstance() {
      return SingletonHolder.sInstance;
    }
    
    private static class SingletonHolder{
    	private static Singleton sInstance = new Singleton();
    }
}

当外部类被加载时,其金泰内部类不会被加载,只有当调用SIngleton.getInstance()方法时,才会加载SingletonHolder并且初始化其成员变量。而类加载时是线程安全的。这样既保证了延迟加载,也保证了线程安全,同时也简化了代码量。

 

五 枚举单例

参考:

https://www.cnblogs.com/yangzhilong/p/6148639.html

http://blog.csdn.net/jeromeliee/article/details/79120373

好处:

1.实例的创建线程安全,确保单例

2.防止被反射创建多个实例

3.没有序列化的问题

/**
 * 使用枚举的单例模式
 *
 * @author yzl
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public class EnumSingleton{
    private EnumSingleton(){}
    public static EnumSingleton getInstance(){
        return Singleton.INSTANCE.getInstance();
    }
    
    private static enum Singleton{
        INSTANCE;
        
        private EnumSingleton singleton;
        //JVM会保证此方法绝对只调用一次
        private Singleton(){
            singleton = new EnumSingleton();
        }
        public EnumSingleton getInstance(){
            return singleton;
        }
    }
}
public static void main(String[] args) {
    EnumSingleton obj1 = EnumSingleton.getInstance();
    EnumSingleton obj2 = EnumSingleton.getInstance();
    //输出结果:obj1==obj2?true
    System.out.println("obj1==obj2?" + (obj1==obj2));
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值