要从单例的出现---->解决安全问题------>解决程序效率低问题,这三个问题理解单例(懒汉式),如果单纯看成熟的代码,会不容易理解...
单例设计模式目的是:类在内存中对象的唯一性!
//假设A,B两个线程并发访问getInstacne()方法,因为有多条语句操作共享数据s,一个在判断一个在赋值。
//当线程A判断为null,此时A线程假设遇到sleep语句睡了一会。被线程B抢到执行权,
//线程B进来也sleep了,A醒后创建一个对象赋给s,B醒了又创建个对象,
//单例的目的要保证一个类在内存中对象的唯一性,new了很多对象,所以不安全。
- class Single
- {
- private static Single s = null;
- private Single(){}
- public static synchronized Single getInstance()
- {
- if(s==null)
- s = new Single();
- return s;
- }
- }
复制代码 //加上synchronized同步锁后,A线程进来,B线程进不来。当A线程new一个对象赋给s出去后,
//B进来判断s不为null,就不new对象,直接返回s使用。这样就解决了安全问题。
//但是如果有n多线程并发访问getInstance()方法想获取实例,每次调用都要判断锁,
//判断锁的次数会很多,导致代码运行速度降低。
- class Single
- {
- private static Single s = null;
- private Single(){}
- public static Single getInstance()
- {
- if(s==null)//用双重判断的方式解决该问题,减少了判断次数,提高了程序效率
- {
- synchronized(Single.class)//使用的锁是该类所属的字节码文件对象
- {
- if(s==null)
- s = new Single();
- }
- }
- return s;
- }
- }
复制代码 //为了解决这个问题,采用双重判断的方式,
//当A线程进来后,先判断s是否为空,如果为空在持有锁后可能sleep一会,B线程没有持有锁,不能进来
//A线程醒后,new一个对象出去释放锁,B线程持有锁进来,判断st不为null,直接使用s,以后其他所有线程调用getInstance()方法,
//判断s不为空,就直接使用s,这种方式锁只判断了一次,解决了程序运行低的问题。
|