0
点赞
收藏
分享

微信扫一扫

Java单例模式

和谐幸福的人生 2022-03-11 阅读 75

Java中创建对象的方式

直接调用构造方法
利用反射调用构造方法
反序列化
克隆
Unsafe实现对象的创建

1:构造方法私有饿汉式单例模式,

/*
 * 饿汉式单例模式
 *
 * 缺点:Unsafe方式现在不好预防
 *
 */
class Single01 implements Serializable {
    private Single01() {
        if (SingleTon!=null){
            //防止反射破坏单例模式
            throw new RuntimeException("请不要试图用反射破坏单例模式");
        }
    }

    private static final Single01 SingleTon = new Single01();

    public static Single01 getInstance(){
        return SingleTon;
    }
	//预防反序列化破坏单例模式
    public Object readResolve(){
        return SingleTon;
    }

}

2:枚举类实现饿汉式单例模式


/*
 * 枚举类实现单例模式
 * 饿汉式的,类一加载就已经创建了单例对象
 *
 * 这时候不会被反序列化破坏
 *
 * 枚举类没有无参构造,也不能用反射破坏
 * 
 * 但是Unsafe还是能够破坏单例模式
 */


enum Sex implements Serializable{
    MALE;//枚举的这个就是唯一的一个单例,就是这个枚举类的单例,默认是public的

    public static void method(){
        System.out.println("实现单例模式");
    }
}

3:DCL懒汉式

/*
 *DCL懒汉式实现单例模式
 */
class Lazy{

    //这个时候必须要加volatile
    //保证可见性,不保证原子性,禁止指令重排序
    /*
    * 为什么这里一定要加volatile一定要加呢?
    *
    * 在单线程下指令重排序是不会影响的,但是多线程下就可能会出现问题
    * */
    private volatile static Lazy lazy=null;

    private Lazy() {
        if (lazy!=null){
            throw new RuntimeException("请不要试图用反射破坏单例模式");
        }
    }

    public static Lazy getInstance(){

        if (lazy==null){
            //首次调用的时候才进行同步,以免影响性能,只有在第一次创建的时候才会存在同步竞争,影响性能,创建好了之后
            //就不会存在同步代码块的调用了,也就没有了性能的损失
            synchronized (Lazy.class){
                //双检锁避免一个同步代码块刚进入,就执行完了。而另一个线程在同步代码块之前进入了第一个if判断,这时候就会创建多个对象。
                if (lazy==null){
                    lazy = new Lazy();
                }
            }
        }
        return lazy;
    }
}

4:内部类懒汉式单例模式

/*
 * 内部类的方式
 * 实现懒汉式单例模式
 */
class staticInner{
    private staticInner() {
    }


    private static class innerClass{
        //静态变量在类加载的时候就初始化了,jvm保证多线程下的安全
        static staticInner inner = new staticInner();
    }

    public static staticInner getInstance(){
        return innerClass.inner;
    }

}
总结一下上面四种方式:
1:饿汉式
2:枚举类饿汉式
3:双检锁懒汉式
4:静态内部类懒汉式

单例模式在jdk中的体现

public static void main(String[] args) throws Exception {
        System.exit(0);
        System.gc();
        /*
         *上面两个方法的底层都是调用了Runtime.getRuntime()的方法
         */
    }
那我们看一下这个类的源码,可以发现这就是饿汉式的单例模式在jdk中的体现
public class Runtime {
    private static Runtime currentRuntime = new Runtime();

    /**
     * Returns the runtime object associated with the current Java application.
     * Most of the methods of class <code>Runtime</code> are instance
     * methods and must be invoked with respect to the current runtime object.
     *
     * @return  the <code>Runtime</code> object associated with the current
     *          Java application.
     */
    public static Runtime getRuntime() {
        return currentRuntime;
    }

    /** Don't let anyone else instantiate this class */
    private Runtime() {}

Collections类中还有大量的单例模式的实现。有很多私有的静态内部类。里面也有枚举实现的单例模式。

举报

相关推荐

0 条评论