《设计模式之单例模式》8中单例模式你都懂吗?

前言

设计模式中的单例模式,大家基本也都会,也都基本上都知道两种实现形式,无外乎饿汉式和饱汉式两种。其实在这两种方式中可以衍生出8中方式。

方式一: 饿汉式

public class Student {

    private static final Student INSTANCE = new Student();

    private Student () {

    }

    public void method(){
        System.out.println("method");
    }

    public static Student getInstance() {
        return INSTANCE;
    }
}

饿汉式,类一加载就实例化对象,私有化构造方法,提供开放的获取实例的方法。该方式也是最为简单也推荐的单例使用方式。

方式二:(和第一种相同)

public class Student {

    private static final Student INSTANCE = null;

	static {
	   INSTANCE = new Student();
	}
	
    private Student () {

    }
    
    public void method(){
        System.out.println("method");
    }

    public static Student getInstance() {
        return INSTANCE;
    }
}

大家会就觉得这两种方式的实现,不管类用不用类一加载就实例化了,占用内存空间,不是太完美,然后就有了下面的饱汉汉式的懒加载方式的单例。

方式三 : 饱汉式

public class Student{

    private static Student INSTANCE = null;

    private Student() {

    }

    public void method(){
        System.out.println("method");
    }

    public static Student getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new Student();
        }
        return INSTANCE;
    }
}

该中方式,实现了在调用的时候,在实例化对象,实现了懒加载,看似很完美了,其实这样会出现线程并发访问时的线程不安全问题。当两个线程同时访问getInstance()方法时,同时看到的INSTANCE都是null,所以两个线程会各自会创建一个新的实例对象。从而引发了我们的第四种实现方式。

方式四:(synchronized同步)

public class Student{

    private static volatile Student INSTANCE = null;

    private Student() {

    }

    public void method(){
        System.out.println("method");
    }

    public static synchronized Student getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new Student();
        }
        return INSTANCE;
    }
}

这种方式采用同步方法的后,实现了线程安全,但是却降低了程序的性能。因为每次调用都要加锁。
那么这用方式有完美的方式吗?那么接下来,我们继续来看方式五。

方式五:(synchronized代码块)

public class Student{

    private static volatile Student INSTANCE = null;

    private Student() {

    }

    public void method(){
        System.out.println("method");
    }

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

这种方式,是不是突然感觉优雅了不少,当我创建实例的时候,我给它加锁,这样不就不是给整个方法加锁了,可以提升一点性能。但是,一说但是,当时还是不完美的,大家仔细想一下,当进入方法体,判断INSTANCE == null 时,还是会出现问题的,此时两个线程并发访问,都通过了if(INSTANCE == null){
这一样代码,还是会各自创建一个实例对象。导致线程不安全。是不是有一种压迫感,问题一个接着一个。没关系啦,接下来,我们就来实现终极的优雅版本。

方法六:(synchronized+ 双重检查)

public class Student{

    private static volatile Student INSTANCE = null;

    private Student() {

    }

    public void method(){
        System.out.println("method");
    }

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

此种方式,也就是线程安全的饱汉式方式了,也是可以推荐使用的。采用双重检查和同步代码块实现,在第一次判断了INSTANCE 是否为null之后,进入同步,此时再次进行判断,如果实例为null,则进行创建新的实例,若不是null了,不做任何操作,直接返回实例。

方式七:(静态内部类的方式)

public class Student{

    private Student() {
    
    }
 
    private static class StudentHolder {
        private final static Student INSTANCE = new Student();
    }

    public void method(){
        System.out.println("method");
    }

    public static Student getInstance() {
        return StudentHolder.INSTANCE;
    }
}

此种方式,使用静态内部类来创建实例对象,从而实现懒加载。当Student类加载的时候,是不会加载StudentHolder类的。只有调用的getInstance方法后才会加载,从而实现懒加载。通过JVM来保证单例。此种方式,也强烈推荐使用。

方式八:(枚举类实现)

public enum Mgr08 {

    INSTANCE;

    public void m() {
        System.out.println("哈哈哈,我成功了");
    }
}

此种方式不仅可以解决线程同步,还可以防止反序列化。也是即为简便的一种方式,但是我个人感觉怪怪的,毕竟好好的一类,整成了一个枚举。也是推荐大家使用。

总结

以上,便是八种单例的实现方式,小编比较推荐使用方式一、方式二、方式六、方式七、方式八,最为推荐使用方式一,简单还安全。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值