Java设计模式:单例模式

前言

之前对设计模式没有太大感受。如今慢慢在工做中愈来愈感受设计模式的重要性,因此决定重头来好好学习整理下经常使用的设计模式。
本文介绍的最初级的一个设计模式 单例模式java

模式说明

java中单例模式定义:一个类有且仅有一个实例,而且自行实例化向整个系统提供。设计模式

应用: 一个系统中多线程对一个文件进行操做,这个文件就须要保证只有一个实例,等等安全

饿汉式

说明:饿汉式意思就是不管系统需不须要使用该类的实例对象,先在类加载的时候建立好
优势:实现简单
缺点:容易形成内存的浪费多线程

经常使用饿汉式

该方式是在该类被加载的时候,就建立好了实例化对象。不容许其余地方经过构造方法来建立对象,只能经过提供的指定公共方法来获取惟一的对象。jvm

public class SingletonDemo1 {

    //static 确保在类加载的时候就会初始化该对象
    private final static SingletonDemo1 singleton = new SingletonDemo1();

    // 必须是私有构造方法,防止其余地方经过构造方法来实例化对象
    private SingletonDemo1(){
    }

    // 是一个公共的静态方法,用于对外提供惟一的对象
    public static SingletonDemo1 getInstance(){
        return singleton;
    }

}

枚举

根据枚举的特性,可使用枚举来实现单例模式学习

public class SingletonDemo3 {

    // 不容许其余地方经过构造方法进行实例化对象
    private SingletonDemo3(){}

    //对外提供可获取惟一实例化对象的公共方法
    public static SingletonDemo3 getInstance(){
        return Singleton.SINGLETON.getInstance();
    }

    private enum Singleton{
        SINGLETON;

        private SingletonDemo3 singleton;

        Singleton(){
            singleton = new SingletonDemo3();
        }

        public SingletonDemo3 getInstance(){
            return singleton;
        }
    }

}

懒汉式

说明:懒汉式意思就是在系统第一次须要使用该类的实例对象时,再建立该类的实例对象。
优势:不形成内存不必的浪费
缺点:实现相对较难.net

懒汉式-线程不安全

在有多线程使用的状况下不要使用,不然可能会形成建立多个实例对象。通常建议不使用该种方式。线程

public class SingletonDemo1 {

    //static 确保在类加载的时候就会初始化该对象
    private static SingletonDemo1 singleton = null;

    // 必须是私有构造方法,防止其余地方经过构造方法来实例化对象
    private SingletonDemo1(){
    }

    // 是一个公共的静态方法,用于对外提供惟一的对象
    public static SingletonDemo1 getInstance(){
        if(singleton==null){
            singleton = new SingletonDemo1();
        }
        return singleton;
    }

}

懒汉式-线程安全-同步方法

因为上面的方式,是在执行getInstance()方法时,多线程使用时可能出现建立多个对象的状况。那能够直接将该方法进行同步,保证任意时间,最可能是能一个线程使用该方法。设计

public class SingletonDemo2 {

    //static 确保在类加载的时候就会初始化该对象
    private static SingletonDemo2 singleton = null;

    // 必须是私有构造方法,防止其余地方经过构造方法来实例化对象
    private SingletonDemo2(){
    }

    // 是一个公共的静态方法,用于对外提供惟一的对象
    public static synchronized  SingletonDemo2 getInstance(){
        if(singleton==null){
            singleton = new SingletonDemo2();
        }
        return singleton;
    }

}

缺点:过重了,每一个线程在每次使用的时候,都须要进行同步,而实际上只是在第一次获取该类的实例对象时须要同步,日后使用不须要同步。

懒汉式-线程安全-双重锁

该方式只会在未实例化对象时,才同步进行实例化对象。实例化后就不须要再进行同步了。

public class SingletonDemo2 {

    //static 确保在类加载的时候就会初始化该对象
    private static volatile SingletonDemo2 singleton = null;

    // 必须是私有构造方法,防止其余地方经过构造方法来实例化对象
    private SingletonDemo2(){
    }

    // 是一个公共的静态方法,用于对外提供惟一的对象
    public static SingletonDemo2 getInstance(){
        if(singleton==null){
            synchronized (SingletonDemo2.class){
                if(singleton==null) { //为了防止多个线程进行实例化
                    singleton = new SingletonDemo2();
                }
            }
        }
        return singleton;
    }

}

有么有注意到,使用了volatitle关键字,为何要使用volatile关键字?
答:这里使用了volatile一个重要的特性——禁止JVM指令重排序
singleton = new SingletonDemo2()的在jvm内存中会有三步,1)分配内存;2)初始化对象;3)将对象指向分配的内存。jvm在会在不改变最终执行结果的状况下对指令进行重排序,即:可能执行顺序是1->3->2,如果在执行执行3还未执行2时,其余线程执行使用,则会报错。
(参考:http://www.javashuo.com/article/p-plwggyio-cp.html

参考资料

http://www.javashuo.com/article/p-qjktkfot-ck.html
http://www.runoob.com/design-pattern/singleton-pattern.html
java实例化对象过程说明:http://www.javashuo.com/article/p-rtbvcfpv-ey.html

相关文章
相关标签/搜索