您的位置:首页 > 编程语言 > Java开发

Java设计模式之Singleton

2016-03-24 16:07 706 查看

单例设计模式(Singleton)是最简单的设计模式。单例模式的核心就是保证全局只有一个实例并且易于访问。单例模式由于全局只会创建一个实例,所以对一些工具类使用单例模式十分适用,比如Android开发中,我们经常需要获取移动设备的高和宽,为了方便管理,我们一般选择把获取的方法封装到一个独立的工具类中,为了避免重复创建,就可以选择使用单例模式。

常用写法:
(1)懒汉式
public class Singleton{
private static Singleton singleton = null;
private Singleton(){
}
publict static Singleton getInstance(){
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}



这种方式的Singleton具有延迟加载的优点,但是缺点也是很明显的,线程不安全!比如:当两个线程并发调用Singleton.getInstance();时假如线程1恰好判断singleton为null,正要创建对象时,JVM将CPU切换给线程2,那么此时singleton仍然为null,所以线程2会创建一个Singleton对象,过了一会儿,线程1被唤醒也会再创建一个Singleton对象,此时就会有两个Singleton对象,不再满足单例的了。所以这是线程不安全的。
(2)同步锁
public class Singleton {
private static Singleton singleton = null;

private Singleton(){
}
public static synchronized Singleton getInstance(){
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}

既然第一种线程不安全,那么我们就加个synchronized,现在线程安全了,不过因为每次调用都需判断同步锁,所以效率有点低~~~
(3)双重检验
public class Singleton {
private static Singleton singleton = null;

private Singleton(){
}
public static Singleton getInstance(){
if(singleton == null){
synchronized(Singleton.class){
if(singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
}
这样似乎解决了效率问题,但对于singleton = new Singleton();的执行,在JVM中大致分为3步:

1.给Singleton的实例分配内存

2.初始化Singleton的构造器

3.将singleton对象指向分配的内存空间

但是在JVM编译过程中会出现指令重排的优化,所以执行顺序的不可控的,可能是1-2-3,也可能是1-3-2.这就可能导致singleton可能还没初始化,就被分配了内存空间。如果两个线程的话,可能线程1执行了1-3还没来的及执行2时,JVM就切换到了线程2,而此时singleton已经不为null了,所以线程2就会直接使用singleton,这样singleton不完整,自然而然就会报错。

(4)饿汉式
public class Singleton {
private static Singleton singleton = new Singleton();

private Singleton(){
}
public static Singleton getInstance(){
return singleton;
}
}

这个并发的问题似乎不好解决,就换个思路,不去解决。o(╯□╰)o。JLS中规定,一个类在一个ClassLoader中只会被初始化一次,这是JVM所保证的,所以就采用这种饿汉式,在类创建时就把实例给创建了,剩下的就不管了(我真TM机智)。开发中应用最多的写法。
(5)内部类式
public class Singleton {

private static class SingletonHolder{
private static Singleton INSTANCE = new Singleton();
}
private Singleton(){
}
public static Singleton getInstance(){
return SingletonHolder.INSTANCE;
}
}
由于SingletonHolder是内部类,所以JVM会保证线程的安全的,同时因为它是私有的,所以是基于懒汉式的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: