首页 > 代码库 > 单例模式在多线程下的多种实现模式
单例模式在多线程下的多种实现模式
单例模式是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修饰的成员变量在每次被线程访问时, 都强迫 从共享内存中 重读 该成员变量的值。
//而且,当成员变量发生变化时,强迫 线程将变化值 回写到共享内存。这样在任何时刻,
//两个不同的线程总是看到某个成员变量的同一个值。
单例模式在多线程下的多种实现模式