您的位置:首页 > 其它

关于多线程中单例模式的使用学习笔记

2017-06-24 20:17 337 查看
最近在学习设计模式中的单例模式,写下此篇总结,权当笔记。

单例模式是一种常见的设计模式。为了保持程序运行时jvm中单例对象只存在一个,这样的方式有这些优点:省去了繁多的new关键字的使用,节省了系统的开销,减轻了CG回收的压力,在有的系统中要求只能拥有一个实例,只有这样才能控制系统的核心逻辑不会错。

在使用单例模式时,可以使用如下例子的方法创建:

public class Single{
//使用static 修饰类的实例
private static Single sin = null;

//构造方法私有化,防止直接实例化
private Single(){}

//创建静态方法,返回本类的实例
public static Single getSingle(){
if(sin==null){
sin = new Single();
}
return sin;
}
}


以上例子可以满足基本的要求,但是如果考虑多线程时,只有上述例子的措施还是不够的。试想在线程A使用getSingle方法创建实例时,线程B也运行到了getSingle这个方法,都判断sin为null,也就都会创建sin这个实例。这对于使用final修饰的sin对象来说,是不符合java的语法的。为解决这个问题,我们想到使用synchronized关键自实现线程互斥。现将getSingle方法改造如下:

public static Single getSingle(){
synchronized(sin){
if(sin == null){
sin = new Single();
}
}
return sin;
}


使用关键字似乎可以完成期望,但是jvm在完成赋值和创建对象上是不同步的,也就是说在sin实例化的时候,jvm先申请了一个空内存,然后直接赋值给sin(这是jvm还没有对sin进行实例化)。这样sin就不null,线程B就不经过sin对象的实例化,但这是sin对象实际只是一个空的内存引用。这样线程B在后续的程序运行中就会出现问题。

其实比较完善且常使用的方式是这样的:

public class Single{
private static class SingleFactory{
private static Single sin = new Single();
}
public static getSingle(){
return SingleFactory.sin;
}
}


这个改进的例子原理是,在类加载时,加载过程中是线程互斥的。这样,就保证了实例过程中的线程互斥。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: