设计模式:单例模式

书上对单例模式的定义:
保证一个类仅有一个实例,并提供一个访问它的全局访问点。

通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象,一个最好的办法就是,让类自身负责保存它的唯一实例,这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。

这里我想跟大家说下我在书上看到一句话,当我们在构建软件的世界中遇到问题时,我们从现实生活中寻找答案,以及现实生活中很多的可行解,都能从软件的世界中得到启发。大家共勉。

首先防止new 把类的构造方法声明为private, 这样外部就不能通过new来构建新的实例了。其次提供一个全局访问点,即声明一个用static修饰获取的方法来访问。
第一种单例,这种方法又叫做懒汉式,线程不安全的。

public class Singleton1 {

    private static Singleton1 instance;

    private Singleton1(){

    }

    public static Singleton1 GetInstance(){

        if(instance == null){

            instance = new Singleton1();
        }

        return instance;
    }

}

测试

 public static void main(String[] args) {

        Singleton1 singleton1 = Singleton1.GetInstance();

        Singleton1 sin2 = Singleton1.GetInstance();

        System.out.println(singleton1 == sin2);

    }
结果:
true

第二种,对第一种方法进行改进,使让其线程安全 于是进行加锁,这样就防止多个线程越过if==null的情况,再多次创建线程。

public class Singleton2 {

    private static  final  Object obj = new Object();
    private static Singleton2 instance;

    private Singleton2(){

    }

    public static Singleton2 GetInstance(){

        synchronized (obj){

            if(instance == null){

                instance = new Singleton2();
            }
        }
        return instance;

    }

}

测试:

public class Main extends Thread{

    @Override
    public void run() {
        System.out.println(Singleton2.GetInstance().hashCode());
    }


    public static void main(String[] args) {

      /*  Singleton1 singleton1 = Singleton1.GetInstance();

        Singleton1 sin2 = Singleton1.GetInstance();

        System.out.println(singleton1 == sin2);
*/
        for(int i = 0;i<6;i++){

            Thread myThread = new Main();
            myThread.start();

        }



    }

}

结果:
2124340618
2124340618
2124340618
2124340618
2124340618
2124340618              //代表线程安全,实现了单例

上面这种性能降低了。为了增加点性能,于是将锁的粒度精细,但是,要预防死锁。
第三种: 采用网上的双重检测判空 但是这个不一定保证对,因为不是原子操作。所以多个线程操作第一判断非null时可能会直接返回一个还未分配完内存的地址。解决办法是给变量加上volatile.

public class Singleton3 {

    private static Singleton3 instance;

    private static  final  Object obj = new Object();

    private Singleton3(){

    }

    public static Singleton3 GetInstance(){

        if(instance == null){

            synchronized (obj){

                if(instance == null){

                    instance = new Singleton3();
                }

            }


        }

        return instance;

    }

}

测试:测试代码和上面一样

1372676747
1372676747
1372676747
1372676747
1372676747
1372676747

第四种,推荐网上的静态内部类的方法

public class Singleton4 {

    private static Singleton4 instance;
    private Singleton4(){

    }
    private static class SingletonInner{

        private static final Singleton4 INSTANCE = new Singleton4();
    }
    public  static final  Singleton4 getInstance(){

        return SingletonInner.INSTANCE;
    }

}

测试代码不附上了。
同时为什么这个模式能保证延迟初始化,又能保证单例,保证线程安全,根据虚拟机规范来保证。请参考:
https://blog.youkuaiyun.com/mnb65482/article/details/80458571

还有一种方法,即通过类的初始化来保证单例

public class Singleton5 {


    private static Singleton5 instance = null;

    private Singleton5(){}

    static{
        instance = new Singleton5();
    }

    public static Singleton5 getInstance() {
        return instance;
    }
}

最后一种就是枚举来实现

枚举实现,每个实例默认都是static final的.

public class Single {

    private enum EnumSingleton {
        INSTACE;
     
        private Single single;
        private EnumSingleton() {
            this.single = new Single();
        }

        private Single getInstance() {
            return single;
        }


    }

    public static Single getInstance() {
        return EnumSingleton.INSTACE.getInstance();
    }

    public static void main(String[] args) {

        Single a = EnumSingleton.INSTACE.getInstance();
        Single b = EnumSingleton.INSTACE.getInstance();
        

        System.out.println("a==b"+(a == b));
 
    }

结果:a==btrue

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值