为了账号安全,请及时绑定邮箱和手机立即绑定

Java高频面试题分享(二)——手写单例模式

标签:
Java

面试题:手写单例模式

单例模式是最常用的设计模式之一,代表唯一,代表实例。

单例设计模式,即某个类在整个系统中只能有一个实例,对象可被获取和使用的代码模式。

例如:代表 JVM 运行环境的 Runtime 类。

可参考我的博客《设计模式-单例模式》

单例模式的要点:

  • 某个类只能有一个实例
    • 构造器私有化
  • 类必须自行创建整个实例
    • 含有一个该类的静态变量来保存这个唯一的实例
  • 类必须自行向整个系统提供这个实例
    • 对外提供获取该实例对象的方式

单例模式可以分为饿汉式和懒汉式两大类。

饿汉式:直接创建对象,不存在线程安全问题

  • 1、直接实例化饿汉式(简洁直观)
  • 2、静态代码块饿汉式(适合复杂实例化)
  • 3、枚举式(最简洁)

懒汉式:延迟创建对象

  • 4、线程不安全式(适用于单线程)
  • 5、双重校验式,线程安全(适用于多线程)
  • 6、静态内部类式(适用于多线程)

第一种形式的示例代码:

public class Singleton1 {
    public final static Singleton1 singleton = new Singleton1();

    private Singleton1() {

    }
}

第二种形式的示例代码:

适合复杂的初始化代码,如从配置文件中读取配置。

public class Singleton2 {
    public final static Singleton2 INSTANCE;
    static {
        INSTANCE = new Singleton2();
    }
    private Singleton2() {

    }
}

第三种形式的示例代码:

利用枚举类的特点,编译时创建单例对象。

public enum Singleton3 {
    INSTANCE
}

第四种形式的示例代码:

单线程下安全,进入 if 语句的线程可能不止一个。

public class Singleton4 {
    private static Singleton4 INSTANCE;

    private Singleton4() {

    }

    public static Singleton4 getInstance() {
        if (INSTANCE == null) {
            // 线程睡眠,便于多线程环境下测试
            // try {
            //    Thread.sleep(100);
            // } catch (InterruptedException e) {
            //    e.printStackTrace();
            // }
            INSTANCE = new Singleton4();
        }
        return INSTANCE;
    }
}

第五种形式的示例代码:

增加线程同步关键字,来避免上面单线程中创建多个对象的问题。

public class Singleton5 {
    private static Singleton5 INSTANCE;

    private Singleton5() {

    }

    public static Singleton5 getInstance() {
        // 缩小 synchronized 关键字的作用范围
        synchronized (Singleton4.class) {
            if (INSTANCE == null) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                INSTANCE = new Singleton5();
            }
        }

        return INSTANCE;
    }
}

优化版本:

使用双重校验,提高性能。

public class Singleton5 {
    private static Singleton5 INSTANCE;

    private Singleton5() {

    }

    public static Singleton5 getInstance() {
        // 第一次创建单例对象时需要保护,创建完成后就只需要判断一下就行了
        if (INSTANCE == null) {
            synchronized (Singleton4.class) {
                if (INSTANCE == null) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    INSTANCE = new Singleton5();
                }
            }
        }

        return INSTANCE;
    }
}

第六种形式的示例代码:

在内部类被加载和初始化时,创建单列对象,且只创建一次。

public class Singleton6 {
    private Singleton6() {

    }

    static class Inner {
        private static final Singleton6 INSTANCE = new Singleton6();
    }

    public static Singleton6 getInstance() {
        return Inner.INSTANCE;
    }
}

六种单例方式的测试代码:

public class TestSingleton {
    @Test
    public void testSingle01() throws ExecutionException, InterruptedException {
        // 多线程测试
        Callable<Singleton1> call = new Callable<Singleton1>() {
            @Override
            public Singleton1 call() throws Exception {
                return Singleton1.INSTANCE;
            }
        };
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        Future<Singleton1> f1 = executorService.submit(call);
        Future<Singleton1> f2 = executorService.submit(call);
        Singleton1 s1 = f1.get();
        Singleton1 s2 = f2.get();
        System.out.println(s1 == s2); // false,创建了多个单例对象
        System.out.println(s1);
        System.out.println(s2);
        executorService.shutdown();
    }

    @Test
    public void testSingle02() throws ExecutionException, InterruptedException {
        // 多线程测试
        Callable<Singleton2> call = new Callable<Singleton2>() {
            @Override
            public Singleton2 call() throws Exception {
                return Singleton2.INSTANCE;
            }
        };
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        Future<Singleton2> f1 = executorService.submit(call);
        Future<Singleton2> f2 = executorService.submit(call);
        Singleton2 s1 = f1.get();
        Singleton2 s2 = f2.get();
        System.out.println(s1 == s2); // false,创建了多个单例对象
        System.out.println(s1);
        System.out.println(s2);
        executorService.shutdown();
    }

    @Test
    public void testSingle03() throws ExecutionException, InterruptedException {
        // 多线程测试
        Callable<Singleton3> call = new Callable<Singleton3>() {
            @Override
            public Singleton3 call() throws Exception {
                return Singleton3.INSTANCE;
            }
        };
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        Future<Singleton3> f1 = executorService.submit(call);
        Future<Singleton3> f2 = executorService.submit(call);
        Singleton3 s1 = f1.get();
        Singleton3 s2 = f2.get();
        System.out.println(s1 == s2); // false,创建了多个单例对象
        System.out.println(s1);
        System.out.println(s2);
        executorService.shutdown();
    }

    @Test
    public void testSingle041() {
        // 单线程测试
        Singleton4 s1 = Singleton4.getInstance();
        Singleton4 s2 = Singleton4.getInstance();
        System.out.println(s1 == s2); // true,只创建了一个单例对象
        System.out.println(s1);
        System.out.println(s2);
    }

    @Test
    public void testSingle042() throws ExecutionException, InterruptedException {
        // 多线程测试
        Callable<Singleton4> call = new Callable<Singleton4>() {
            @Override
            public Singleton4 call() throws Exception {
                return Singleton4.getInstance();
            }
        };
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        Future<Singleton4> f1 = executorService.submit(call);
        Future<Singleton4> f2 = executorService.submit(call);
        Singleton4 s1 = f1.get();
        Singleton4 s2 = f2.get();
        System.out.println(s1 == s2); // false,创建了多个单例对象
        System.out.println(s1);
        System.out.println(s2);
        executorService.shutdown();
    }

    @Test
    public void testSingle05() throws ExecutionException, InterruptedException {
        // 多线程测试
        Callable<Singleton5> call = new Callable<Singleton5>() {
            @Override
            public Singleton5 call() throws Exception {
                return Singleton5.getInstance();
            }
        };
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        Future<Singleton5> f1 = executorService.submit(call);
        Future<Singleton5> f2 = executorService.submit(call);
        Singleton5 s1 = f1.get();
        Singleton5 s2 = f2.get();
        System.out.println(s1 == s2); // true,只创建了一个单例对象
        System.out.println(s1);
        System.out.println(s2);
        executorService.shutdown();
    }

    @Test
    public void testSingle06() throws ExecutionException, InterruptedException {
        // 多线程测试
        Callable<Singleton6> call = new Callable<Singleton6>() {
            @Override
            public Singleton6 call() throws Exception {
                return Singleton6.getInstance();
            }
        };
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        Future<Singleton6> f1 = executorService.submit(call);
        Future<Singleton6> f2 = executorService.submit(call);
        Singleton6 s1 = f1.get();
        Singleton6 s2 = f2.get();
        System.out.println(s1 == s2); // true,只创建了一个单例对象
        System.out.println(s1);
        System.out.println(s2);
        executorService.shutdown();
    }
}
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
6197
获赞与收藏
1548

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消