---------------------- android培训、java培训、期待与您交流! ----------------------
开发中,常用到Singleton 单例设计模式,他解决了一个类在内存中只能有一个对象,那么怎样保证对象的唯一性呢?
我们可以把这个类唯一的构造函数私有化,让他不能创建对象,也不能被继承,那怎样创建对象呢?只能在本类中先创建对象,
然后对外提供一个公共的获取实例的方法。
先看第一种写法,饿汉式的写法:
public class Singleton {
private static Singleton instance = new Singleton();
//other fields…
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
//other methods…
}
1、 Singleton类的只有一个构造方法,它是被private修饰的,客户对象无法创建该类实例。
2、 我们为此单例实现的全局访问点是public static Singleton getInstance()方法,注意,instance变量是私有的,外界无法访问的。 我们也可以定义instance变量是public的,这样把属性直接暴露给其他对象,就没必要实现public static Singleton getInstance()方法,但是可读性没有方法来的直接,而且把该实例变量的名字直接暴露给客户程序,增加了代码的耦合度,如果改变此变量名称,会引起客户类的改变。 如果该实例需要比较复杂的初始化过程时,最好把这个过程应该写在static{…}代码块中。
3、 此实现是线程安全的,当多个线程同时去访问该类的getInstance()方法时,不会初始化多个不同的对象,这是因为,JVM(Java Virtual Machine)在加载此类时,对于static属性的初始化只能由一个线程执行且仅一次[1]。
由于此单例提供了静态的公有方法,那么客户使用单例模式的代码也就非常简单了,如下所示:
Singleton singleton = Singleton.getInstance(); //这种写法比较简单常用,因为只有一条执行语句,不会产生多线程安全问题,所以也称作“饿汉式”
二、单例设计模式的另一种写法,懒汉式,从字面上理解,他比较懒,也就是这个类一初始化的时候并不会直接创建该类的实例,只有调用该类获取对象的方法是,才创建了该类对象,也称为对象的延迟加载,俗称“懒汉式”,那么我们可以这样写:
乍一看没问题,这个写法在单线程中确实没有问题,但是在多线程中,可能出现创建一个以上对象的情况:
class Single
{
private static Single s = null;
private Single(){}
public static Single getInstance()
{
if(s==null) // t1 t2两个线程
{ // Thread.sleep(10);假设 t1 cpu执行到这里, 这时t2线程进来了,也执行到这里挂了,t1醒了 new个对象,t2又醒了,他直接向下执行,也new 个对象
s=new Single();
}
return s;
}
}
怎么解决呢?多线程同步函数可以解决,某一时刻,同步函数内只能有一个线程执行,必须这个线程执行完,另一个线程才能进来
class Single
{
private static Single s = null;
private Single(){}
public static synchronized Single getInstance()
{
if(s==null)
{
s=new Single();
}
return s;
}
}
这样写就安全了,但程序的效率也大大降低了,因为任何一个线程进来都要判断锁,怎样才能减少判断锁的次数呢?我们只要把多个线程要访问的共享数据加锁就行了,
没必要整个函数都加锁,这样写:
class Single
{
private static Single s = null;
private Single(){}
public static Single getInstance()
{
if(s==null) //一旦new 对象,这就不为null,就不再判断锁了,相比同步函数大大提高了效率
{
synchronized(Single.class) //静态的同步方法,使用的锁是该方法所在类的字节码文件对象。即类名.class
{
if(s==null)
s = new Single();
}
}
return s;
}
}
最后对单例设计模式的总结:
单例模式有两种:一种是饿汉式,另一种是懒汉式。
有什么区别(面试):懒汉式的特点在于实例的延迟加载。
懒汉式延迟加载有什么问题:有,如果多线程访问时会出现安全问题,怎么解决,可以加同步来解决;可以加同步来解决,用同步代码块和同步函数都行,但稍微有些低效,用双重判断能解决效率问题。
那么加同步的时候使用的锁是哪一个呢?该类所属的字节码文件对象。
注意:这里是在同一个JVM中,才能保证一个类只有一个单例,如果在分布式环境中,整个应用(可能分布在不同JVM上),这样写是不OK的。
---------------------- android培训、 java培训、期待与您交流! ----------------------详细请查看: http://edu.csdn.net/heima