您的位置:首页 > 其它

单例模式

2015-09-14 15:18 344 查看
对于单例模式探讨,网上的大牛,都给了很多不同视角的解释。本篇博客,仅仅是对他们观点的一个总结。

下面我将分三步,来一起学习一下单利模式。

(1)它要解决一个什么问题:

对于这个问题的理解,由于自己的经验原因,认识的并不深刻,从别人的观点来看,它是为了解决不一致的状态。(这个在实际工作当中遇到后,再修改本文)

(2)它有什么特点:

1.自己创建自己的实例

2.类只能被实例化一次,实例唯一.

3.可以被其他所有类调用

(3)它是如何实现的:

1.最简单的实现

先不考虑,线程安全,性能,我们来写一个最基本的单例模式的类

(饿汉单例)

public class Singleton{

private static final Singleton singleton=new Singleton();

public static Singleton getSingleton(){

return singleton;

}

}

2.性能的优化

这段代码可以简单的创建一个实例,也就是在JVM加载上述类的时候,就会创建一个Singleton实例,也就是不管我们用不用它,它自己就会创建自己,这样的类如果数量少还好,当有很多的时候,就会占用资源.

既然是它是自动的创建,那我们手动创建不就好了吗?!

为此我们可以简单的修改以上代码

(懒汉单例)

public class Singleton{

private static Singleton singleton=null;

public static Singleton getSingleton(){

if(singleton==null){

singleton=new Singleton();

}

return singleton;

}

}

3.线程同步

上面这段代码我们可以在单线程的情况下简单,便捷的创建一个Singleton实例,但是当在多线程的条件下,上边的创建方式就会出现问题。

我们来分析一下多线程可能出现的问题的原因.现在有线程A和线程B两个线程,当A执行以上代码判断singleton为null,就在此时cup时间片切换,b线程也执行到这一块,此时对于线程A它并没有实例化,所以b线程此时也会判断它为null进而实例化singleton,这时候问题就出现了,A线程B线程都会实例化Singleton,有两个singleton存在.(当然,这里还有很多问题需要考虑,程序的原子性,可见性.但是为了简化问题,我们不做探究,以后再做修改),

为了解决线程同步问题,我们可以给方法加一个锁.

public class Singleton{

private static Singleton singleton=null;

public static Singleton getSingleton(){

synchronize(Singleton.class)

{

if(singleton==null){

singleton=new Singleton();

}

}

return singleton;

}

}

4.性能

上面的代码成功的解决了线程同步的问题(还有其他方式),但是问题又来了,要知道synchronize是很消耗资源的,我们每次获取Singleton实例的时候,都会synchronize

。可见这样并不是一个很好的方式,我们回想一下刚才开始时,我们也需要到了优化性能的问题,避免自动Singleton自动实例化,我们加入if判断手动的进行实例化,因此我们也可以这样修改先判断是否已经实例化,再进行线程同步

public class Singelton{

public static Singleton singleton=null;

public static Singleton getSingleton(){

if(singleton==null){

synchronize(Singleton.class){

if(singleton==null){

singleton=new Singleton();

}

}

}

return singleton;

}

}

5.总结

单例模式简单的说可以分为两种,也就是上边懒汉单例,饿汉单例,饿汉单例因为在加载的时候实例化Singleton对象,所以天然的线程安全,懒汉单例的线程是不安全的,所以上面我们也讨论了一下解决办法。

当然关于单例模式还有一些 比如 通过静态内部类:

public class Singleton {

private static class LazyHolder {

private static final Singleton INSTANCE = new Singleton();

}

private Singleton (){}

public static final Singleton getInstance() {

return LazyHolder.INSTANCE;

}

}

利用了classloader的机制来保证初始化instance时只有一个线程,所以也是线程安全的,同时没有性能损耗。(以上引述




一个本科小生的奋斗史

) 对于这种机制 不是特别熟悉 以后再做
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: