设计模式之单例设计模式

单例设计模式

单例设计模式主要有饿汉式,懒汉式,注册式,容器式几种。

(1)饿汉式
由于会在加载时候就存入到内存,会对内存浪费,不适合使用在一些批量所有类进行加载时候使用,例如spring加载所有工程项目类。如只有几个类的时候可以使用。
设计模式之单例设计模式_第1张图片
设计模式之单例设计模式_第2张图片

(2) 懒汉式
懒汉式相比饿汉式更节省资源内存,但如果不做任何控制会出现线程不安全。因为在判断单例一瞬间多个线程进入后会创建多次实例,出现问题。
设计模式之单例设计模式_第3张图片

解决方案:
<一>,加锁(syncronized),对创建方法时候进行加入syncronized进行阻塞,但弊端会出现性能降低,所有访问对象都要进行排队一个个进行创建实例,会出现性能瓶颈。就算将锁加到方法里面,看样子虽然解决了,但是又出现了线程安全问题。所以需要用到双重检查锁
设计模式之单例设计模式_第4张图片

设计模式之单例设计模式_第5张图片

<二>,双重检查锁,判断外部是否为空,避免后续所有对象都进行加锁对性能造成的影响,同时内部又保证线程同时进入判断后释放锁以后重新创建造成的线程安全问题。
设计模式之单例设计模式_第6张图片

<三>,静态内部类,虽然看起来很像饿汉式,但其实是调用getInstance()时候才会发现lazyHolder有个静态类重新加载,所以是懒汉式。
优点:写法优雅,利用JAVA本身语法特点,性能高,避免了内存浪费
缺点:能够被反射破坏单例。(图2有解决破坏单例方式)
设计模式之单例设计模式_第7张图片
设计模式之单例设计模式_第8张图片

(3) 注册式单例
最优雅最安全的一种单例写法,再声明枚举类时候就已经将实例存入了枚举内部核心的map中了,可以通过枚举的构造方法的name(相当于key) 从map中获取实例。虽然最为优雅但是同时也面临了饿汉式的内存浪费情况,不过只是方式不同,饿汉式是直接将对象指向了内存中,而枚举类则是在初始化时候创建了一个核心带有volitail的map将所有单例都存放到了枚举的map中。因内存浪费的问题故而再次升级,就是我们使用的spring IOC容器。
设计模式之单例设计模式_第9张图片

(4) 容器式单例
针对大批量单例对象进行创建场景所使用的。对于枚举式单例创建所升级创建方式。但会有线程安全问题。并且不管容器式单例还是枚举式单例都会面临序列化破坏单例的情况。但可以在进行序列化类中重写readResovle方法(名字必须一致),再次反序列化时候就会解决序列化破坏单例情况。

设计模式之单例设计模式_第10张图片
设计模式之单例设计模式_第11张图片设计模式之单例设计模式_第12张图片

(5) ThreadLocal单例
只是针对线程内的安全单例,实现每个线程都是安全单例,但多线程时候非同一个对象,从而实现线程隔离。例如数据库的thread链接对象等。与传统的线程非安全单例不同,该单例确保每个线程能独享一个单例,而传统非线程安全的单例只是不保证线程安全,但同时也保证不了每个线程能独享一个单例

设计模式之单例设计模式_第13张图片

你可能感兴趣的:(设计模式和设计原则)