设计模式之单例模式
来源:互联网 发布:路由器ip绑定mac地址 编辑:程序博客网 时间:2024/06/08 01:25
什么时候采用单例模式:
当某个类只需要一个实例的时候,比如一台电脑 可以连接多个打印机,但是一个时间段只能有一个打印服务。
单例模式保证一个类仅有一个实例,并提供一个访问它的全局访问点。
通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。一个最好的办法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且他可以提供一个访问该实例的办法。
-:表示private +:表示public
1. 单例类(此处的单例类是懒汉式单例类,其处理方式是在第一次被引用时,才会将自己实例化,所以被称为懒汉式单例类)
public class Singleton {private static Singleton instance;//构造方法让其private,这就堵死了外界利用new创建此类实例的可能private Singleton(){ }//此方法是获得本类实例的唯一全局访问点public static Singleton GetInstance(){//若实例不存在,则new一个新实例,否则返回已有的实例if(instance==null){instance=new Singleton();}return instance;}}
public class Main {public static void main(String[] args) {// TODO Auto-generated method stubSingleton s1=Singleton.GetInstance();Singleton s2=Singleton.GetInstance();if(s1==s2){System.out.println("两个对象是相同的实例");}elseSystem.out.println("两个对象不是相同的实例");}}
说明:单例模式保证了唯一的实例。
2. 多线程时的单例
认真思考会发现,上面的例子存在问题,比如,在多线程的程序中,多个线程同时访问Singleton类,调用GetInstance()方法,会有可能造成创建多个实例。
解决办法:加锁,在GetInstance 方法上加上synchronized 。所有这个类的加了 synchronized 的方法,在执行时,会获得一个该类的唯一的同步锁,当这个锁被占用时,其他的加了 synchronized 的方法就必须等待
public static synchronized Singleton GetInstance(){//若实例不存在,则new一个新实例,否则返回已有的实例if(instance==null){instance=new Singleton();}return instance;}
这段代码使得对象实例由最先进入的那个线程创建,以后的线程在进入时不会再去创建对象实例。这就保证了多线程环境下的同时访问也不会造成多个实例的生成。
但是它仍然存在问题:每次调用GetInstance 方法都会加锁,这样会影响性能。同步方法是对方法的整体进行加锁,对运行效率来讲很不利,因此考虑采用同步代码块。
改进办法:双重锁定
3.双重锁定
双重锁定:不用让线程每次都加锁,而是在实例被创建的时候再加锁处理。同时也保证了多线程的安全。这种做法被称为Double-Check Locking (双重锁定)
public static Singleton GetInstance(){if(instance==null){synchronized(Singleton.class){if(instance==null){instance=new Singleton();}}}return instance;}
那为什么上面在同步里面还要做一次instance实例是否存在的判断呢?
因为当instance为null时,并且存在同时有两个线程调用GetInstance 方法时,它都将可以通过第一重instance的判断,然后由于同步机制,这两个线程只有一个可以进入,另一个在外排队等候,必须要其中一个进入并出来后,另一个才能进入。而此时如果没有第二重的instance是否为null的判断,则第一个线程创建了实例,而第二个线程还是可以继续创建新的实例,这就没有达到单例的目的。
4.饿汉式单例类饿汉式单例类:采用以下静态初始化方式在自己被加载时就将自己实例化,所以被形象地称为饿汉式单例类
public class Singleton2 { private static final Singleton2 instance=new Singleton2();private Singleton2(){ }//此方法是获得本类实例的唯一全局访问点public static Singleton2 GetInstance(){return instance;}}
5.静态内部类实现单例模式
懒汉模式考虑线程安全需要在获取单例的方法添加synchronized关键字实现同步代码块,这样造成了性能损耗;而饿汉模式不能延迟实例化对象,下面是一个静态内部类单例模式的实现,既保证了线程的安全,有能够延迟加载,也就是在第一次使用的时候加载。
public class Singleton3 {private Singleton3(){}public static Singleton3 GetInstance(){return Singleton3Handler.instance;}private static class Singleton3Handler{private static final Singleton3 instance = new Singleton3();}}
6.三者对比
1.由于饿汉式,即静态初始化的方式,它是类一加载就实例化的对象,所以要提前占用系统资源。
2.懒汉式会面临多线程访问的安全性问题,需要做双重锁定这样的处理才可以保证安全。
3.静态内部类单例模式的实现,既保证了线程的安全,有能够延迟加载
4.到底使用哪一种方式,取决于实际的需求。
测试代码:
public class MyThread extends Thread{/** * @param args */public static void main(String[] args) {// TODO Auto-generated method stubMyThread t1=new MyThread();MyThread t2=new MyThread();MyThread t3=new MyThread();t1.start();t2.start();t3.start();}@Overridepublic void run() {for(int i=0;i<5;i++){System.out.println(Singleton.GetInstance().hashCode());}}}
参考资料:
1.《大话设计模式》 程杰
2.http://blog.csdn.net/jason0539/article/details/23297037
- 设计模式之 单例设计模式
- 设计模式之 单例设计模式
- 设计模式之单例设计模式
- 设计模式之-----------单例设计模式
- 设计模式之:单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之-单例设计模式
- 设计模式之单例设计模式 标签: 设计模式
- 设计模式之单例
- 设计模式之单例
- 设计模式之 单例
- Python 数据类型转换操作
- js 右键菜单
- Oracle笔记(十三) 视图、同义词、索引
- new People { { "rr", "ss" } }是什么?
- MySql数据库索引原理
- 设计模式之单例模式
- Java中的面试题 [2] --- Java框架、SpringMVC、Spring、mybatis、hibernate等
- 关于char和varchar的查询效率问题
- 蓝桥杯:写日志
- 阮一峰老师-CSS 变量教程
- Stack的三种含义-阮一峰
- Oracle笔记(十四) 用户管理
- Rider新预览版对F#的支持让人眼前一亮
- WIN32学习——菜单消息