设计模式:解决某一类问题最行之有效的方式。Java中有23中设计模式。单例设计模式目的:解决一个类在内存中对象的唯一性。
解决方案:
1.为了避免其他程序过多建立该类对象,先禁止其他程序建立该类对象
2.还为了让其他程序可以访问该类对象,只好在本类中自定义一个对象
3.为了方便其他程序对自定义对象的访问,可以对外提供一些访问方式。
以上三个步骤实现过程:
1.将构造函数私有化,
2.在类中创建一个本类对象,3.提供一个方法,可以获取该对象
单力设计模式有两种模式:“饿汉式”和“懒汉式”。
饿汉式:类一经加载进内存就创建对象。如代码示例-1
class Single
{
private static final Single s = new Single();
private Single(){}
public static Single getInstance()
{
return s;
}
}
懒汉式:类加载后没有创建对象,类调用getInstance方法后创建对象,这种现象叫做对象的延迟加载。如代码示例-2
class Single
{
private static Single s = null;
private Single(){}
public static Single getInstance()
{
if(s==null)
s = new Single();
return s;
}
}
但是懒汉式,在多线程中会出现安全问题。假设A,B两个线程并发访问getInstacne()方法,因为有多条语句操作共享数据s,一个在判断另一个在赋值。当线程A判断为null,此
时A线程假设遇到sleep语句睡了一会。被线程B抢到执行权,线程B进来也sleep了,A醒后创建一个对象赋给s,(if语句只判断一次)B醒后向下执行,又创建个对象。单例设计模
式的目的要保证一个类在内存中对象的唯一性,new了很多对象,所以不安全。此时想到了同步,将getInstance()函数变为同步函数,这样A线程进来后,B线程就进不来。所
以当A线程new一个对象赋给s出去后,B进来判断s不为null,就不new对象,直接返回s使用。这样就解决了安全问题,如代码示例-3
class Single
{
private static Single s = null;
private Single(){}
public static synchronized Single getInstance()
{
if(s==null)
s = new Single();
return s;
}
}
但是又考虑到,如果有n多线程并发访问getInstance()方法想获取实例,每次调用都要判断锁,判断锁的次数会非常多,导致代码运行速度降低。为了解决这个问题,采用双重
判断的方式,当A线程进来后,先判断s是否为空,如果为空在持有锁后可能sleep一会,B线程没有持有锁,不能进来A线程醒后,new一个对象出去释放锁,B线程持有锁来,
判断st不为null,直接使用s,以后其他所有线程调用getInstance()方法,判断s不为空,就直接使用s,这种方式锁只判断了一次,解决了程序运行低的问题。如代码示例-4
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;
}
}