java基础_设计模式_单例模式二(详解6种写法)

大家好,我是野猪。

题目:设计一个类,我们只能生成该类的一个实例。

第一种:只适用于单线程环境

单利模式最简单的也是不会用的写法

特征:只适用于单线程环境

问题:当2个线程同时运行到instance·是否为null的if语句,并且instance的确没有创建的时候 那么2个线程都会创建一个实例。

java代码:

public class Singleton1 {

    private Singleton1() {
    }

    private static Singleton1 singleton1 = null;

    public static Singleton1 getInstance() {
        if (singleton1 == null) {
            singleton1 = new Singleton1();
        }
        return singleton1;
    }
}

第二种:多线程环境中能工作但是效率不高

双重加锁 适合多线程但是因为加锁耗时导致效率很低
特征:加上了同步锁
问题:由于在一个时刻只有一个线程能拿到同步锁,当A线程拿到同步锁的时候,B线程只能等待
当A线程发现没有创建实例就会去创建实例,代码走完,然后A线程释放同步锁;然后B线程家加上同步锁,并运行接下来的代码;
现在存在一个问题就是A线程加上同步锁并创建完实例后B线程完全没有必要再加锁走判断有没有实例了。 ps:加锁是一个非常耗时的操作,在没有必要的时候应尽量避免。

java代码:

public class Singleton2 {

    private Singleton2() {
    }

    private static Singleton2 singleton2 = null;

    public static Singleton2 getInstance() {
        //加上同步锁
        synchronized (Singleton2.class) {
            if (singleton2 == null) {
                singleton2 = new Singleton2();
            }
        }

        return singleton2;
    }
}


第三种:加同步锁前后两次判断实例是否已经存在

特征:为了避免A线程获取到同步锁后创建了实例,然后释放锁;B线程获取到同步锁,接着走判断的是否创建实例的情况;因为加锁耗时。
加锁之前判断一次有没有实例;
在首次没有创建实例的情况下,现在A线程获取同步锁创建实例,释放锁;B线程线先判断有无实例,有则不用运行接下来的代码了。

Java代码:

public class Singleton3 {

    private Singleton3() {
    }

    private static Singleton3 singleton3 = null;

    public static Singleton3 getInstance() {
        if (singleton3 == null) {
            //加上同步锁
            synchronized (Singleton3.class) {
                if (singleton3 == null) {
                    singleton3 = new Singleton3();
                }
            }
        }

        return singleton3;
    }
}
双重加锁是比较常用的一种写法,确保了多线程环境下只创建一个实例,并且用两个if判断提高效率。

第四种:饿汉式单列

特征:在类初始化的时候 已经自行实例化; 
问题:并不是当你需要才实例化 降低内存的使用率
ps:Java中的静态代码块是在虚拟机加载类的时候,就执行的,而且只执行一次。
     非静态代码块是在类new一个实例的时候执行,而且是每次new对象实例都会执行。

java代码:

public class Singleton4 {

    private Singleton4() {
    }

    private static Singleton4 singleton4 = new Singleton4();

    public static Singleton4 getInstance() {

        return singleton4;
    }
}

第五种:饿汉式单列的变种 静态代码块

特征:跟第四种是一样的 都是在类初始化时即实例化instance

java代码:

public class Singleton5 {

    private Singleton5() {
    }

    private static Singleton5 singleton5 = null;

    static {
        singleton5 = new Singleton5();
    }

    public static Singleton5 getInstance() {

        return singleton5;
    }
}

第六种:静态内部类

特征:静态内部类 改善了3和4的饿汉式 因为3、4 都是类加载的时候就实例化instance 降低了内存使用效率。
只有在真正需要的时候才会创建实例,提高空间使用效率
因为内部类Nested{}没有被主动使用,只有调用getInstance()的时候才会去实例化instance。
这就避免了类加载的时候就实例化instance
举例:假设实例化instance很消耗资源,而类中有其他的方法我需要调用,如果类一加载就实例化的话,那太消耗资源了。所以做到真正需要的时候才去创建实例最好。

java代码:

public class Singleton6 {

    private Singleton6() {
    }

    public static Singleton6 getInstance() {

        return Nested.instance;
    }

    private static class Nested {

        public static Singleton6 instance = new Singleton6();

    }
}

以上是自己简单总结的常见的单例模式的写法,希望对大家有所帮助。在上一篇中简单的说了一下单例模式存在的因素和使用的地方,链接如下:

点击打开链接



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值