设计模式之单例模式
来源:互联网 发布:网络有利还是有害 编辑:程序博客网 时间:2024/06/05 01:58
一、核心作用:
保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。
二、优点:
1、由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决;
2、单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理。
三、应用场景:
1、Windows的Task Manager(任务管理器)就是很典型的单例模式;
2、Windows的Recycle Bin(回收站)也是典型的单例应用,在整个系统运行过程中,回收站一直维护着仅有的一个实例;
3、项目中,读取配置文件的类,一般也只有一个对象,没有必要每次使用配置文件数据,每次new一个对象去读取;
4、网站的计数器,一般也是采用单例模式实现,否则难以同步;
5、应用程序的日志应用,一般都采用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加;
6、数据连接池的设计一般也是采用单例模式,因为数据连接是一种数据库资源;
7、操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统;
8、在servlet编程中,每个Servlet也是单例;
四、常见的五种单例模式实现方式:
主要:
-饿汉式(线程安全,调用效率高。但是,不能延时加载)
-懒汉式(线程安全,调用效率不高。但是,可以延时加载)
其它:
-双重检测式(由于JVM底层内部模型原因,偶尔会出问题。不建议使用)
-静态内部类式(线程安全,调用效率高。但是,可以延时加载)
-枚举单例式(线程安全,调用效率高,不能延时加载)
五、代码(java实现):
/** * 饿汉式单例模式 * 线程安全,调用效率高。但是,不能延时加载 * @author ly1 * */public class Singleton1 { private static Singleton1 instance = new Singleton1(); private Singleton1(){ } public static Singleton1 getInstance(){ return instance; }}
/** * 懒汉式单例模式 * 线程安全,调用效率不高。但是,可以延时加载 * @author ly1 * */public class Singleton2 { private static Singleton2 instance; private Singleton2(){ } public static synchronized Singleton2 getInstance(){ if(instance == null){ instance = new Singleton2(); } return instance; }}
/** * 双重检测单例模式 * 由于JVM底层内部模型原因,偶尔会出问题。不建议使用 * @author ly1 * */public class Singleton3 { private static Singleton3 instance; private Singleton3(){ } public static Singleton3 getInstance(){ if(instance == null){ synchronized(Singleton3.class){ if(instance == null){ instance = new Singleton3(); } } } return instance; }}
/** * 静态内部类单例模式 * 线程安全,调用效率高,可以延时加载,结合了饿汉式与懒汉式的优点 * @author ly1 * */public class Singleton4 { private static class Holder{ private static final Singleton4 instance = new Singleton4(); } public Singleton4 getInstance(){ return Holder.instance; } private Singleton4(){ }}
/** * 枚举实现单例模式 * 线程安全,调用效率高,不能延时加载。JVM底层保证单例。 * @author ly1 * */public enum Singleton5 { INSTANCE; //其它操作 private void operation(){ }}
/** * 单例模式的测试,这里只测试第一个饿汉式单例模式 * @author ly1 * */public class Client { public static void main(String[] args) { Singleton1 s1 = Singleton1.getInstance(); Singleton1 s2 = Singleton1.getInstance(); System.out.println(s1 == s2); }}结果:true
六、五种单例模式调用效率的测试:
/** * 测试五种单例模式的调用效率,这里测的是第一种,其它的类似 * @author ly1 * */public class PerformanceTest { public static void main(String[] args) throws Exception { int threadNum = 10; //记录开始时间 long start = System.currentTimeMillis(); //管理线程 final CountDownLatch count = new CountDownLatch(threadNum); //开启十个线程,每个线程调用1亿次 for (int i = 0; i < threadNum; i++) { new Thread(new Runnable(){ @Override public void run() { for (int j = 0; j < 100000000L; j++) { Object obj = Singleton5.INSTANCE; } count.countDown(); } }).start(); } //保证main线程在这十个线程执行完后再执行 count.await(); //记录结束时间 long end = System.currentTimeMillis(); System.out.println("总耗时:" + (end - start) + "ms"); }}
测试结果:
分析:
1、可以看出懒汉式由于在方法上加了同步锁,导致每次调用都要同步,性能大大降低。
2、如果创建对象资源耗时,要求延时加载,建议选择静态内部类式;
3、如果不要求延时加载,建议选择枚举式。
七、其他相关问题
以上五种方式,除了枚举式,其他的都可以用反射和反序列化破解,造成不是单例。
-反射,虽然构造器私有化,依然还是可以调用。(参考)
-反序列化,先将对象通过对象流写入到文件中,再用对象流读取,会创建新的对象。(关于对象流)
当然,写普通的项目,不用考虑这些,这里只是提一下。
- 设计模式之 单例设计模式
- 设计模式之 单例设计模式
- 设计模式之单例设计模式
- 设计模式之-----------单例设计模式
- 设计模式之:单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之-单例设计模式
- 设计模式之单例设计模式 标签: 设计模式
- 设计模式之单例
- 设计模式之单例
- 设计模式之 单例
- C++引用&概念及用法
- 异常
- 剑指offer--链表中倒数第k个结点-java
- UDP传输中文乱码、异常解决
- C++成员变量的初始化顺序问题
- 设计模式之单例模式
- Android入门——利用Canvas完成绘制点、圆、直线、路径、椭圆、多边形等2D图形
- 微信公众平台初试
- 九度OJ 1533 最长上升子序列 (基于贪心和二分查找)
- android studio 代码修复提示快捷键
- 用链表实现队列
- java内省机制及PropertyUtils使用方法
- iOS中的动画总体预览
- jQuery源码分析之$.index函数