Java 面试之单子模式

1.Java 面试之单子模式

单子模式要满足以下几点

1, 构造函数私有化,使得不能通过new来实例化对象
2,通过new在类的内部创建唯一的实例化对象
3,定义一个公有的静态的方法来返回上一部的对象

单子模式分为懒汉模式和饿汉模式

饿汉模式*

以下通过代码来讲解什么饿汉模式

public class Single {
    //1 私有构造器。外部不能访问
    private Single(){

    }
    //2 声明一个静态的自己的类
    private static Single single = new Single();
    //3 返回一个返回自己类的方法
    public static Single getInstance(){
        return single;
    }
}

测试类:打出实例化之后的对象地址

public class Test {
    public static void main(String[] args) {
        Single single1 = Single.getInstance();
        Single single2 = Single.getInstance();
        System.out.println(single1);
        System.out.println(single2);
    }

}

运行结果

:Test.main()
csdn.Single@15db9742
csdn.Single@15db9742

发现地址都一样,说明实例化的是一个对象
特点是不管对象有没有为空,直接实例化

懒汉模式

public class Single2 {
    private Single2(){}
    private static Single2 single2;

    public static Single2 getInstance(){
        if(single2==null){
            single2 = new Single2();
        }
        return single2;
    }
}

public class Test {
    public static void main(String[] args) {
        Single2 single1 = Single2.getInstance();
        Single2 single2 = Single2.getInstance();
        System.out.println(single1);
        System.out.println(single2);
    }

}

运行结果:

:Test.main()
csdn.Single2@15db9742
csdn.Single2@15db9742

可以看出地址是一样的,懒汉模式一旦第一次实例化成功后,这个对象就不动了,因为是static
还有就是因为要判断一次对象是否为空,这也是他和饿汉的区别,他相比较,实例化比较温柔

但是由于在多线程操作下,对象判空这一项会受到多线程的影响,可能线程a进行了实例化但是线程b同时进行判空就会发生错误,所以就要对实例化判断进行同步锁的注入
代码:

public class Single3 {
    private static Single3 single3;
    private Single3(){}
    public static Single3 getInstance(){
        synchronized (Single3.class){
            if(single3==null){
                single3 = new Single3();
            }
        }
        return single3;
    }
}

这样就解决了多线程并发的错误
但还是缺点:每次调用方法时都要加锁,而加锁很耗时,所以在保证对象为null时只new出一个实例时加锁就够了
改进如下:

public class Single4 { private static Single4 single4;
    private Single4(){}
    public static Single4 getInstance(){

            if(single4==null){
                synchronized (Single4.class){
                    if(single4==null){
                        single4 = new Single4();
                    }
                }
            }

        return single4;
    }
}

静态代码块

在静态代码块中加入对该自身对象的实例化,因为JDK会在静态代码区中对其代码仅执行一次

public class Single5 {
    private Single5(){}
    private static Single5 single5;
    static{//本身就是线程同步且仅执行一次
        single5 = new Single5();
    }
    //这里不需要加锁,因为他会在jdk区进行单线程的实例化
    public static Single5 getInstance(){
        return single5;
    }

}

结果:

:Test.main()
csdn.Single5@15db9742
csdn.Single5@15db9742

静态代码按需创建(静态内部类)

如果按上面的方法,在执行静态方法后会对程序产生影响,为了避免这个问题,改进一个内部类的手段进行优化:

public class Single6 {
    private Single6(){}
//建立内部类
    private static class Nested{
        private static Single6 single6;
        static{
            single6 = new Single6();
        }
    }


    public static Single6 getInstance(){
        return Nested.single6;
    }

}

以上就是所有的单子模式,欢迎补充

你可能感兴趣的:(日记)