您的位置:首页 > 其它

设计模式——单例模式

2016-05-01 11:58 330 查看

单例模式

  若一个类在整个程序的运行期间仅能有一个实例,则多个线程对此实例的访问必须考虑线程安全的问题。对于一些互斥性的唯一性的资源类,通常使用单例模式,从而防止进入不一致状态。

单线程环境下的懒汉式单例

//该方法在多线程下可能会创建出多个实例,由此仅适用于单线程环境
public class Singleton {
//私有静态成员,属于类的成员,一个类就这么一个
private static Singleton single = null;
//私有构造方法,仅能内部自己使用,外界无法访问,由此外界无法创建该类的实例
private Singleton() {
...
}
//对外提供的公共接口,返回类的唯一实例
public static Singleton getInstance() {
if(single == null) {
//多个线程可能会同时进入此方法,从而导致多例
single = new Singleton();
}
return single;
}
}


多线程下的懒汉式单例

public class Singleton {
private static Singleton single = null;
private Singleton () {
...
}
//关键字synchronized修饰的方法,同一时刻只能有一个线程进入访问。在线程退出该方法之前,其它任何线程不能进入访问
public static synchronized Singleton getInstance() {
if(single == null) {
single = new Singleton();
}
return single;
}
}


  上述直接给整个方法加锁,每次执行都要同步。若加锁之前先判断实例是否为空,为空时才会加锁同步,不为空时不需要加锁同步,可保证仅在第一次创建实例的时候同步,以后不会再同步,效率明显提高。

synchronized(Object) {
//参数Object为对象锁。任何一个Object子类的对象都可以作为对象锁。一个线程必须持有对象锁才可以进入代码块执行。
...
}


  对象锁肯定是synchronized(Object) {…}代码块所属的类的一个成员。这个成员应该是静态的,属于类,为类的唯一成员,被类的全部实例共享。若对象锁为普通成员,则每个类的实例都有一个自己的对象锁,那不同的线程使用同一个类的不同的实例的时候不能保证线程安全。可以者直接定义一个静态对象来作为对象锁使用,如:

public static Object o = new Object(),synchronized(o) {...}


public class Singleton {
private static Singleton single = null;
private Singleton () {
...
}
public static Singleton getInstance() {
//最外层的判空,是为了明确是否需要同步操作,这一步可能会有多个线程同时进入
if(single == null) {
//使用Singleton类内的静态Class类型的实例作为锁,这一步只能有一个线程进入,谁获得了锁,谁就能进入
synchronized(Singleton.class) {
//获得锁后,要进一步判空,因为可能有多个进程都进入了之前的同步操作。第一个进程得到锁进入判空创建实例后,释放锁。第二个进程进入判空后,判空无需再创建实例
if(single == null) {
single = new Singleton();
}
}
}
return single;
}
}


多线程下的饿汉式单例

  在类加载的时候就直接创建类的实例,直接省去了同步的操作。静态成员在类加载的时候会初始化。普通成员在创建类的实例的时候才会初始化,因为它们属于实例不属于类。

public class Singleton {
//静态成员隶属类,加载即初始化。定义为final,初始化后不可再改变或初始化
private static final Singleton INSTANCE = new Singleton();
private Singleton() {
...
}
public static Singleton getInstance() {
return INSTANCE;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: