美文网首页
Java设计模式:单例模式

Java设计模式:单例模式

作者: vczyh | 来源:发表于2018-09-07 19:03 被阅读0次

Java设计模式——单例模式

1、饿汉模式

public class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton() {
    }
    public static Singleton newInstance() {
        return instance;
    }
}  

将对象构建放在了static语句中,JVM加载类的时候会执行静态语句和静态代码块,而且虚拟机保证类只被初始化一次,所以类的初始化是单线程执行的,所以这种是线程安全的,缺点就是初始化太早,可能造成空间浪费。

2、懒汉模式,延迟加载

public class Singleton {
    private static Singleton instance;
    private Singleton() {
    }
    public static Singleton newInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

在加载类的时候不会进行实例化,在获取实例的话,如果为空,则进行实例化,单线程不会出问题,多线程可能会创建多个实例,造成不是单例,可以进行改进:

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

使用synchronized控制线程同步访问

3、双重校验锁

上述模式实现了延迟加载和线程安全,但是由于使用synchronized会造成性能下降,因为同时只有一个进程可以调用newInstance()方法,采用双重校验锁可以提高性能

public class Singleton {
    private static Singleton instance;

    private Singleton() {
    }

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

synchronized并没有加在方法上,一般情况下,当俩个线程执行newInstance()方法,判断instance都为null时,就会创建俩个不同的实例,所以为了解决这个问题,所以在同步代码块中还得加入验证instance == null代码。

这里还有一个问题,由于Java的指令重排优化的存在,instance = new Singleton()语句不具有原子性,他是分几步执行的:

1.给对象分配内存空间
2.在内存空间创建对象
3.将对象引用赋值给instance

2必须在1之后执行,但是3和2之间没有依赖关系,程序执行的时候顺序可以是1->2->3,也可能是1->3->2

如果是单线程程序,无论执行的顺序是什么,使用instances的时候,虚拟机可以保证它是初始化完成的

如果是多线程程序,一个线程在执行instance = new Singleton()的时候,其他的线程是要执行第一个if (instance == null)语句的,因为这个语句在同步锁的外面,这个时候就涉及到执行顺序:
如果按1->2->3执行,在执行3之前,instance的引用一直都是null,如果这时候第二个线程执行newInstance()方法,就会一直在同步代码块外面等待,直到同步代码块执行完3后,第二个线程进入,判断instance不为空,然后执行return语句,返回的是第一个线程初始化的对象,这是正确的。
如果按1->3->2执行,执行完3但是还没有执行2的时候,第二个线程执行newInstance()方法,由于现在的instance已经有了引用对象,不是null,所有第二个线程不会在同步代码块外面等待,会直接执行return语句,此时返回的instance还没有完成初始化,是错误的对象。

上面的问题就是因为JVM的自动优化操作,可以使用volatile禁止指令重排优化,也就是保证先分配空间,然后赋值引用,代码如下:

public class Singleton {
    private static volatile Singleton instance;

    private Singleton() {
    }

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

4、静态内部类

public class Singleton {
    
    private static class SingletonHolder {
        public static Singleton instance = new Singleton();
    }
    
    private Singleton() {}
    
    public static Singleton newInstance() {
        return SingletonHolder.instance;
    }
    
}

不会在一开始就加载静态内部类SingletonHolder,其他地方使用SingletonHolder的时候才会加载,比如第一次调用newInstance()方法,从而实现了延迟加载。和饿汉模式一样,也利用了类加载机制,所以可以保证线程安全。

5、枚举

public enum Singleton {
    INSTANCE;
}

相关文章

  • JAVA设计模式 - 单例模式

    JAVA设计模式 - 单例模式 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一...

  • 单例模式

    JAVA设计模式之单例模式 十种常用的设计模式 概念: java中单例模式是一种常见的设计模式,单例模式的写法...

  • Java中单例模式你用的哪一种?

    一起讨论java中的单例模式。单例模式是java设计模式中算是最简单的设计模式了。 * java实现单例模式的写法...

  • JAVA设计模式之单例模式

    JAVA设计模式之单例模式

  • 设计模式

    Java 设计模式情景分析 ——单例模式 Java 设计模式情景分析——建造者模式 Java 设计模式情景分析——...

  • Java设计模式教程

    Java设计模式教程 Java工厂设计模式 Java抽象工厂模式 Java单例模式 Java建造者(Builder...

  • 设计模式——单例模式

    设计模式——单例模式 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一,这种类型...

  • 设计模式

    单例模式 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式...

  • 设计模式《一》单例模式

    单例模式 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属...

  • 设计模式之单例模式详解(附源代码)

    单例模式 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属...

网友评论

      本文标题:Java设计模式:单例模式

      本文链接:https://www.haomeiwen.com/subject/xeqhgftx.html