什么是单例模式? html
顾名思义,就是只有一个实例,也就是说一个应用程序中只有一个实例对象.java
既然一个系统,一个应用程序中只有一个实例,那么也就说明了若是操做这一个对象,必然涉及到共享资源,涉及到资源分配问题,资源竞争等问题. 数据库
那么咱们的应用场景是什么呢?设计模式
1. 网站的在线人数. 网站的在线人数在某一个时刻,全部人看到的是同样的, 是这个网站这个时刻,全部用户所共享的.安全
2. 池化技术. 好比数据库的链接池. 每一个数据库的可支持的链接数量是有限,并且链接对象建立和销毁也是比较耗内存的. 经过一个统一的入口去控制,能够保证对数据库的压力在可控的范围内,同是也能够保证出具库链接的持续使用.并发
3. 配置中心. 一个应用程序针对经过一个配置文件的加载只须要加载一次便可,不须要屡次加载.网站
其实以上只是一些常见的应用场景,固然单例模式的应用场景也远不止于此.this
本文参考的博客地址为:http://www.javashuo.com/article/p-fcozwjup-gn.html线程
参考的博客的写的很不错, 若是想了解更多,能够去看看这篇参考的博客设计
接下来咱们来看一下常见的实现方式,以及其中的对比.
饿汉式,即直接初始化好,使用的时候直接调用便可.
package com.cbl.design.singletondesign; public class HungrySingleton { private static final HungrySingleton singleton = new HungrySingleton(); //限制外部产生HungrySingleton对象 private HungrySingleton(){ } //向外提供获取示例的静态方法 public static HungrySingleton getInstance() { return singleton; } }
懒汉式, 顾名思义,就是懒,须要的时候再去初始化
package com.cbl.design.singletondesign; public class LazySingleton { private static volatile LazySingleton singleton = null; private LazySingleton() { } public static LazySingleton getSingleton() { //不用每次获取对象都强制加锁,为了提高了效率 if (singleton == null) { synchronized (LazySingleton.class) { if (singleton == null) { singleton = new LazySingleton(); } } } return singleton; } }
静态内部类的方式
package com.cbl.design.singletondesign; public class StaticInnerSingleton { /** * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例 * 没有绑定关系,并且只有被调用到时才会装载,从而实现了延迟加载。 */ private static class Singleton2Holder { /** * 静态初始化器,由JVM来保证线程安全 */ private static StaticInnerSingleton singleton = new StaticInnerSingleton(); } private StaticInnerSingleton() { //System.out.println("singleton2 private construct method called"); } public static StaticInnerSingleton getSingleton() { //System.out.println("singleton2 getSingleton method called"); return Singleton2Holder.singleton; } private String name; public void desc() { //System.out.println("singleton2 desc method called"); } }
还有一种实现方式是依赖于枚举, 咱们知道枚举中的对象是实例化好的,并且枚举天生要求枚举类的构造器必须私有,并且自己仍是被final 修饰的, 不可被继承
package com.cbl.design.singletondesign; public enum EnumSingleton { INSTANCE; public String getDesc() { return "desc"; } public static void process() { System.out.println("static process method"); } private String name; private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
以上是4中常见的构造单例模式的四种线程安全的构造单例的设计模式.网上可能还有其他的非线程安全的构建单例的方法, 可是线程安全的主要就是这四种.
(1) : 饿汉式 : 加载类的时候就会进行实例化,,若是后续没有用到,则会搞成资源浪费.
(2) : 懒汉式 : 使用的时候再去初始化,这样在前几回调用并发调用的时候,会出现资源竞争, 等待时间较久,可是后续再次调用的时候, 因为是双重判断加加锁校验机制, 不会出现阻塞.
(3): 静态内部类 : 也是在使用的时候再去加载内部类并初始化外部类的对象,第一次调用会比较慢.
(4):枚举单例: 类加载的时候就穿建立好对象了, 特色和饿汉式很像.
上面是这几种单例方式的特色,其中懒汉式,饿汉式,静态内部类的方式都不能防止反射,只有枚举类能够防止反射.
可是通常咱们的应用程序只须要保证能够正常实现单例便可,不必过多的去防止单例模式,咱们使用单例模式,就是想构造单例对象的,可是咱们本身又去使用反射去破坏单例模式,这不是本身给本身找麻烦吗.