单例模式
哈哈哈。。。刚刚有位同学说单例模式,如何去应用。这个单例模式在我们项目中,常常被用到。比较特殊的一种设计模式。因为我们大家知道我们的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关键字锁定的是对象,在用的时候,一定要在恰当的地方使用。注意需要使用锁的对象和过程,可能有的时候并不是整个对象及整个过程都需要锁。总之,单例模式的创建有好多种形式。只要满足单例模式特点的对象创建都可以叫单例。具体项目,具体使用。