单例模式

来源:互联网 发布:linux删除组命令 编辑:程序博客网 时间:2024/06/05 18:50

设计思想

其实只需要三步就可以保证对象的唯一性:
1、不允许其他程序用new对象
因为new就是开辟新的空间,在这里更改数据只是更改的所创建的对象的数据,如果可以new的话,每一次new都产生一个对象,这样肯定保证不了对象的唯一性。
2、在该类中创建对象
因为不允许其他程序new对象,所以这里的对象需要在本类中new出来。
3、对外提供一个可以让其他程序获取该对象的方法
因为对象是在本类中创建的,所以需要提供一个方法让其它的类获取这个对象。
那么这三步怎么用代码实现呢?将上述三步转换成代码描述是这样的:
1、私有化该类的构造函数
2、通过new在本类中创建一个本类对象
3、定义一个公有的方法,将在该类中所创建的对象返回

实现代码

单例模式的写法大的方面可以分为5种五种:
①饿汉式②懒汉式③双重校验锁④静态内部类⑤枚举
接下来我们就一起来看看这几种单例设计模式的代码实现,以及它们的优缺点。

饿汉式[可用]

顾名思义,饿汉法就是在第一次引用该类的时候就创建对象实例,而不管实际是否需要创建。

代码如下:
public class Singleton {    private static Singleton = new Singleton();    private Singleton() {}    public static getSignleton(){        return singleton;    }}
访问方式: 
Singleton instance = Singleton.getInstance();  
得到这个实例后就可以访问这个类中的方法了。
优点:从它的实现中我们可以看到,这种方式的实现比较简单,在类加载的时候就完成了实例化,避免了线程的同步问题。

缺点:由于在类加载的时候就实例化了,所以没有达到Lazy Loading(懒加载)的效果,也就是说可能我没有用到这个实例,但是它也会加载,会造成内存的浪费(但是这个浪费可以忽略,所以这种方式也是推荐使用的)。

饿汉式(变种)[可用]

代码如下:
public class Singleton{    private static Singleton instance = null;    static {        instance = new Singleton();    }    private Singleton() {};    public static Singleton getInstance() {        return instance;    }}
访问方式:
Singleton instance = Singleton.getInstance();
得到这个实例后就可以访问这个类中的方法了。
这种写法被称为饿汉式,因为它在类创建的时候就已经实例化了对象。其实饿汉式(变种)和饿汉式只是写法有点不同,都是在类初始化时创建对象的,它的优缺点和饿汉式一样,可以归为一种写法。

懒汉式(线程不安全)[不可用]

代码如下:
public class Singleton {    private static Singleton instance=null;    private Singleton() {};    public static Singleton getInstance(){        if(instance==null){            instance=new Singleton();        }        return instance;    }}
这种方式是在调用getInstance方法的时候才创建对象的,所以它比较懒因此被称为懒汉式。

这种写法是最简单的,由私有构造器和一个公有静态工厂方法构成,在工厂方法中对instance进行null判断,如果是null就new一个出来,最后返回instance对象。这种方法可以实现延时加载,但是有一个致命弱点:线程不安全。如果有两条线程同时调用getInstance()方法,就有很大可能导致重复创建对象。

懒汉式(线程安全)[不推荐]

代码如下:
public class Singleton {    private static Singleton instance=null;    private Singleton() {};    public static synchronized Singleton getInstance(){        if(instance==null){            instance=new Singleton();        }        return instance;    }}
缺点:效率太低了,每个线程在想获得类的实例时候,执行getInstance()方法都要进行同步。而其实这个方法只执行一次实例化代码就够了,后面的想获得该类实例,直接return就行了。方法进行同步效率太低要改进。

双重校验锁(懒汉式变种)[推荐用]

代码如下:
public class Singleton {    private static volatile Singleton singleton = null;    private Singleton(){}    public static Singleton getSingleton(){        if(singleton == null){            synchronized (Singleton.class){                if(singleton == null){                    singleton = new Singleton();                }            }        }        return singleton;    }}
访问方式:
Singleton instance = Singleton.getInstance();
得到这个实例后就可以访问这个类中的方法了。
Double-Check概念对于多线程开发者来说不会陌生,如代码中所示,我们进行了两次if (singleton== null)检查,这样就可以保证线程安全了。这样,实例化代码只用执行一次,后面再次访问时,判断if (singleton== null),直接return实例化对象。
优点:线程安全;延迟加载;效率较高。

静态内部类[推荐用]

代码如下:

public class Singleton{    private Singleton() {};    private static class SingletonHolder{        private static Singleton instance=new Singleton();    }    public static Singleton getInstance(){        return SingletonHolder.instance;    }}

访问方式:

Singleton instance = Singleton.getInstance();
得到这个实例后就可以访问这个类中的方法了。


这种方式跟饿汉式方式采用的机制类似,但又有不同。两者都是采用了类装载的机制来保证初始化实例时只有一个线程。不同的地方在饿汉式方式是只要Singleton类被装载就会实例化,没有Lazy-Loading的作用,而静态内部类方式在Singleton类被装载时,并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonHolder类,从而完成Singleton的实例化。


类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。


优点:避免了线程不安全,延迟加载,效率高。

枚举[推荐用]

代码如下:

public enum SingletonEnum {     instance;     private SingletonEnum() {}     public void method(){     }}

访问方式:
SingletonEnum.instance.method();
可以看到枚举的书写非常简单,访问也很简单在这里SingletonEnum.instance这里的instance即为SingletonEnum类型的引用所以得到它就可以调用枚举中的方法了。

使用枚举除了线程安全和防止反射强行调用构造器之外,还提供了自动序列化机制,防止反序列化的时候创建新的对象。因此,Effective Java推荐尽可能地使用枚举来实现单例。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 成年了还是很皮怎么办 三岁儿子太调皮怎么办 10个月宝宝粘人怎么办 6个月宝宝粘人怎么办 9个月宝宝偏矮怎么办 1岁宝宝粘人爱哭怎么办 宝宝2岁半胆小怎么办 5岁宝宝超级粘人怎么办 狗狗吃饭要人喂怎么办 十个月宝宝认人怎么办 一岁宝宝粘人怎么办 9个月宝宝粘妈妈怎么办 一岁的宝宝呕吐怎么办 宝宝一岁八个月太粘人了怎么办 六个月的宝宝好粘人怎么办 两岁半宝宝说话突然结巴了怎么办 1岁宝宝突然呕吐怎么办 宝宝吃坏了呕吐怎么办 1岁宝宝吃饭爱玩怎么办 7岁儿童半夜呕吐怎么办 一个月宝宝粘人怎么办 2岁宝宝太粘人了怎么办 8个月宝宝很粘人怎么办 7个月宝宝呕吐是怎么办 一个月婴儿粘人怎么办 八个月小孩粘人怎么办 一岁的宝宝粘人怎么办 六个月宝宝粘人爱哭怎么办 摔伤结巴里面灌脓了怎么办 两周半的宝宝说话结巴怎么办 孩子两周说话结巴怎么办 名字取了生僻字考大学怎么办 淘宝客服一直不说话怎么办 淘宝客服不说话也不发货怎么办 面对不说话的客人怎么办? 卖家客服不回复怎么办 2周小孩说话结巴怎么办 微信群里只领红包不说话的人怎么办 躺在微信不说话的客户怎么办 9岁儿童说话结巴怎么办 5岁儿童说话结巴怎么办