码迷,mamicode.com
首页 > 编程语言 > 详细

单例模式在多线程下的多种实现模式

时间:2017-03-07 22:28:09      阅读:201      评论:0      收藏:0      [点我收藏+]

标签:单线程   class   final   变化   线程安全   strong   代码   利用   实例   

单例模式是23种设计模式中比较常见的设计模式,又因为其代码量精简,所以经常会被用在在面试中测试面试者的能力。

初级的单例模式很简单

实现两个要求

1构造方法私有化

2对外提供静态的,公开的获取对象的方法

所以:初级单例模式如下

public class Singelton {
private Singelton(){}
private static Singelton sin=null;
public static Singelton getSingelton(){
           if(sin==null){
               sin=new Singelton();
          }
return sin;
}

}

----------------------------------------

但是这样就够了吗?

随着学习的深入,我们知道程序大多数在多线程的环境下运行。这就对我们的代码提出了更高质量的要求,要求我们考虑线程安全问题。

仅仅是上面的那段代码无法保证线程的安全。于是:

public class SingletonThread {
private SingletonThread() {}
private static SingletonThread st=null;
public synchronized static SingletonThread getSingletonThread(){
if(st==null){
st=new SingletonThread();
}
return st;
}

}

这段代码考虑到了线程安全,但是,在方法上加锁代价是否太大了?效率与单线程相近,假设这个方法中有上万行代码,在方法上加锁

是很不划算的。

 

所以,我们有更好的方法

1

public final class SingletonOne {//饿汉式,不能实现按需分配
private SingletonOne(){};
private static SingletonOne sin=new SingletonOne();
public static SingletonOne getSingleton(){
return sin;
}
}

利用静态成员仅在类加载阶段执行一次的性质,得到唯一的对象。

此方法不仅线程安全,而且方法简介。

 

2我们能否不一开始就创建类的实例呢?做到按需分配

如下:

public final class SingletonTwo {
private SingletonTwo(){};
public static SingletonTwo setsin(){
return singleton.sin;
}
static class singleton{//内部类不会再外部类加载时加载,故此是按需分配。
private singleton() {};
private static final SingletonTwo sin=new SingletonTwo();

}
}

利用内部类不会在外部类加载时被加载的性质,真正实现了按需分配。

---------------------------------------------

以上两种方法是极好的,但是也需要根据实际情况使用,因为类中的方法和属性都是静态的,已经失去了被继承的意义

故此还有另一种推荐方法:

3

public class SingletonV {
private SingletonV(){}
private volatile SingletonV singleton=null;
public SingletonV getSingleton(){
if(singleton==null){
synchronized (SingletonV.class) {
if(singleton==null){
singleton=new SingletonV();
}
}
}
return singleton;
}
}

这样类还保留了继承的意义,同样要加锁,但是开销小得多。利用了关键字volatile。

具体用法如下

//在当前的Java内存模型下,线程可以把变量保存在本地内存(比如机器的寄存器)中,
//而不是直接在主存中进行读写。这就可能造成一个线程在主存中修改了一个变量的值,
//而另外一个线程还继续使用它在寄存器中的变量值的拷贝,造成数据的不一致。
//要解决这个问题,把该变量声明为volatile(不稳定的)即可,
//这就指示JVM,这个变量是不稳定的, 每次使用它都到 主存中 进行读取。
//一般说来,多任务环境下各任务间共享的标志都应该加volatile修饰。
//Volatile修饰的成员变量在每次被线程访问时, 都强迫 从共享内存中 重读 该成员变量的值。
//而且,当成员变量发生变化时,强迫 线程将变化值 回写到共享内存。这样在任何时刻,
//两个不同的线程总是看到某个成员变量的同一个值。

 

单例模式在多线程下的多种实现模式

标签:单线程   class   final   变化   线程安全   strong   代码   利用   实例   

原文地址:http://www.cnblogs.com/df-happyforever/p/6517009.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!