做简单的网站链接,医院信息化建设会议安排网站,企业网站营销实现方式解读,做动画人设有哪些网站可以借鉴一.单件模式是什么#xff1f; 单件模式也被称为单例模式#xff0c;它的作用说白了就是为了确保“该类的实例只有一个” 单件模式经常被用来管理资源敏感的对象#xff0c;比如#xff1a;数据库连接对象、注册表对象、线程池对象等等#xff0c;这种对象如果同时存在多个…一.单件模式是什么 单件模式也被称为单例模式它的作用说白了就是为了确保“该类的实例只有一个” 单件模式经常被用来管理资源敏感的对象比如数据库连接对象、注册表对象、线程池对象等等这种对象如果同时存在多个的话就会造成各种不一致的麻烦你总不希望发生数据库重复连接的异常吧 二.如何保证类的实例只有一个 这个问题看似简单但如果没有接触过单件模式的话要自己想出来解决方案还是需要一些天赋的。。不信的话可以试着想想。。 1.类的实例可能只有一个吗貌似只要知道类名就可以随便new了吧 当然可以知道类名的话确实可以调用其构造方法来new实例但是注意一点这个类必须要有公开的构造方法才能从外部new实例不是吗 2.那就是说要保证类的实例只有一个的话这个类不能有公开的构造方法对吧 没错就是这样我们需要定义一个私有的构造方法 3.一个没有公开构造方法的类能够产生实例吗如果构造方法是private那么只有该类的实例才能调用这个构造方法同样的要调用这个构造方法才能产生该类的实例。。这不是“鸡生蛋蛋生鸡。。”的问题吗 用私有的构造方法当然可以生产实例上面忽略了一点并不是“只有该类的实例才能调用这个构造方法” 因为在该类内部就可以随便调用这个私有的构造方法并不需要创建任何实例 ------- 有了上面的讨论结果我们就可以实现经典的单件模式了 package SingletonPattern;/*** author ayqy* 最经典的单件模式*/
public class Singleton {private static Singleton instance;//定义静态实例变量/*** 定义私有构造方法防止从外部new实例*/private Singleton(){//初始化操作}/*** 提供全局访问点* return 该类的实例*/public static Singleton getInstance(){if(instance null)instance new Singleton();return instance;}/** 其它有用的属性和行为* 毕竟应用了单件模式的类仍然具有原本的功能* */
}注意一定要清楚最后一点应用了单件模式的类并不应该丧失其原本的功能千万不能为了使用而使用 三.继续思考我们的单件模式 我们的单件模式已经万无一失了吗 不它还存在很多问题比如 1.多线程环境下 2.多个class loader环境下 我们无法保证产生的实例只有一个对吧 但是作为一种成熟的设计模式单件模式必须要能从容应对这些环境所以接下来我们将讨论如何应对这些环境 四.多线程环境下的单件模式 如何在多线程环境下保证实例的唯一性 很容易想到用synchronized关键字来保证线程安全就像这样 /*** 提供全局访问点* return 该类的实例*/
public static synchronized Singleton getInstance(){if(instance null)instance new Singleton();return instance;
}我们把getInstance方法定义为同步方法就保证了不会有多个线程同时进入该方法就不会产生不同的实例了 ------- 但是上面的方法存在致命的问题用synchronized关键字同步方法会极大的降低效率同步一个方法甚至可能造成百倍的效率下降。。这会拖垮我们的程序 有什么好的改进方法呢 首先上面的同步块是整个getIntance方法每次调用该方法都会强制进入同步机制但仔细一想我们只在第一此调用该方法时需要进行同步第一次new对象之后的调用直接返回new好的对象就好了 那么我们的改进方案就是用双重加锁实现只在第一次new对象时进行同步 package SingletonPattern;/*** author ayqy* 多线程下的单件模式2——利用双重加锁保证只在实例化变量的时候进行同步*/
public class DoubleLockSingleton {private static volatile DoubleLockSingleton instance;//定义静态实例变量/*** 定义私有构造方法防止从外部new实例*/private DoubleLockSingleton(){//初始化操作}/*** 提供全局访问点* return 该类的实例*/public static DoubleLockSingleton getInstance(){if(instance null)synchronized(DoubleLockSingleton.class){//进入同步块if(instance null)//再次判空instance new DoubleLockSingleton();}return instance;}/** 其它有用的属性和行为* 毕竟应用了单件模式的类仍然具有原本的功能* */
}注意双重加锁体现在volatile关键字告诉编译器这个变量不能被保留副本一旦发生变动就会强制写回避免了不一致和synchronized修饰的同步块 但要明白这样做的代价volatile关键字也会告诉编译器不要对该对象进行编译优化 只看第一次new对象的过程的话双重加锁的效率甚至要比同步方法更低但在双重加锁方式在以后的调用中不再需要进行同步所以长远看来双重加锁的效率要高于同步方法 ------- 有没有一种方法不需要使用龟速的同步机制就能保证线程安全呢如果有的话绝对能够大大提高效率对吧 当然有这种方法叫做“急切初始化”顺便提一下开篇提到的“经典单件模式”其实用了“延迟初始化”的方法。。很简单不必解释一起看看吧 package SingletonPattern;/*** author ayqy* 多线程环境下的单件模式——用“急切初始化”来保证线程安全*/
public class EagerlyInitSingleton {private static EagerlyInitSingleton instance new EagerlyInitSingleton();//定义静态实例变量并在类加载的时候就进行初始化操作/*** 定义私有构造方法防止从外部new实例*/private EagerlyInitSingleton(){//初始化操作}/*** 提供全局访问点* return 该类的实例*/public static synchronized EagerlyInitSingleton getInstance(){return instance;}/** 其它有用的属性和行为* 毕竟应用了单件模式的类仍然具有原本的功能* */
}额这也能叫方法吗这么做貌似不和标准吧 没关系这种方法自然有它的优点比如 1.效率很高且线程安全 2.简单易用什么都不用考虑甚至不用判断 但其致命的缺点是资源浪费问题如果这个对象是一个巨大的极其耗费资源的对象而我们在一开始就创建了它却迟迟没有用到这将是非常伤的。。 ------- 上面提到了三种保证线程同步的方式如何选择必须要结合具体情况来定应综合考虑效率资源利用等各个因素 五.多个class loader环境下的单件模式 如果存在多个类加载器多个类加载器可能同时加载我们的单件类从而产生多个实例 对于这种情况我们可以显式指定使用哪一个class loader来加载单件类这样就有效避免了上述问题 六.总结 应用单件模式可以保证对象的唯一性但要注意单件模式的适用范围 不应该滥用单件模式因为毕竟需要管理的资源敏感对象不会很多转载于:https://www.cnblogs.com/ayqy/p/3962910.html