单例模式

单例模式

哈哈哈。。。刚刚有位同学说单例模式,如何去应用。这个单例模式在我们项目中,常常被用到。比较特殊的一种设计模式。因为我们大家知道我们的java代码不是直接运行在电脑中的,而是在我们安装JDK中的JVM上运行的。因此为了保证,我们系统开销大小,不占不必要的内存。先人就把这种一生只需实例化一次的对象 直接单独设计一个模型。那就是我们称的单例模型。

一。单例模式:简单称呼,一生只实例化一次的对象。

单例模式必须满足一下特点:

1.必须持有私有静态实例,目的就是为了防止被引用。

2.必须持有私有构造方法,目的就是防止被实例化。

3.必须拥有静态工程方法,目的就是了创建唯一实例。

不安全代码(1):

public class Singleton {  
  
    /* 持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载 */  
    private static Singleton instance = null;  
    /* 私有构造方法,防止被实例化 */  
    private Singleton() {  
    }   
    /* 静态工程方法,创建实例 */  
    public static Singleton getInstance() {  
        if (instance == null) {  
            instance = new Singleton();  
        }  
        return instance;  
    }  
    /* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */  
    public Object readResolve() {  
        return instance;  
    }  
}  

不错代码是我们经常看到的这样子。但是如果要考虑线程的问题的话。我们这样子的代码毫无线程安全保护的类,如果把它放入多线程的中,肯定就会出现问题了。单例模式特殊之处在于,当在线程中运行。因为这样子我们需要考虑线程安全的问题。如果我们singleton方法加synchronized关键字,这样子。因为synchronized关键字锁住的是这个对象,这样的用法,在性能上会有所下降,因为每次调用getInstance(),都要对对象上锁,事实上,只有在第一次创建对象的时候需要加锁,之后就不需要了。

public static Singleton getInstance() {  
        if (instance == null) {  
            synchronized (instance) {  
                if (instance == null) {  
                    instance = new Singleton();  
                }  
            }  
        }  
        return instance;  
    }  

好多人都是这样子写的。这样子写的好处就是当调用的时候是不需要加锁的,只有在instance为null,并创建对象的时候才需要加锁,性能有一定的提升。

但是问题总是有的。我们知道。在Java指令中创建对象和赋值操作是分开进行的,也就是说instance = new Singleton();语句是分两步执行的。但是JVM并不保证这两个操作的先后顺序,也就是说有可能JVM会为新的Singleton实例分配空间,然后直接赋值给instance成员,然后再去初始化这个Singleton实例。这样就可能出错了。

这一句明白的理解就是,A,B同时在锁方法等待。A假如instance是null的话,那么JVK就会给A内存分配。但是还没有实例化。这个时候B进来了。但是B的instance不为null直接去使用对象了,这时候发现,对象为null。还没有实例化。这样子就出错了、因此经过以上的归纳,先人给我们指明了一条道路了。那就是用内部类来维护单例的实现。

单例模式使用内部类来维护单例的实现,JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候,JVM能够帮我们保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕,这样我们就不用担心上面的问题。同时该方法也只会在第一次调用的时候使用互斥机制,这样就解决了低性能问题

public class Singleton {  
  
    /* 私有构造方法,防止被实例化 */  
    private Singleton() {  
    }  
  
    /* 此处使用一个内部类来维护单例 */  
    private static class SingletonFactory {  
        private static Singleton instance = new Singleton();  
    }  
  
    /* 获取实例 */  
    public static Singleton getInstance() {  
        return SingletonFactory.instance;  
    }  
  
    /* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */  
    public Object readResolve() {  
        return getInstance();  
    }  
}  

这样子是好了写,但是如果 构造函数中抛出异常,实例将永远得不到创建。哈哈哈哈。。就这样子吧。、注意一点就是synchronized关键字锁定的是对象,在用的时候,一定要在恰当的地方使用。注意需要使用锁的对象和过程,可能有的时候并不是整个对象及整个过程都需要锁。总之,单例模式的创建有好多种形式。只要满足单例模式特点的对象创建都可以叫单例。具体项目,具体使用。

原文地址:https://www.cnblogs.com/huojg-21442/p/6950534.html