JavaSE面试题02:单例设计模式

简介: JavaSE面试题02:单例设计模式

单例设计模式

之前文章有提到过单例设计模式的初步介绍Java设计模式之单例设计模式

下文提到的枚举Java中的枚举类是什么?enum关键字怎么使用?

线程池Java多线程10—如何使用线程池创建线程?

涉及到的Java多线程09—实现Callable接口创建线程

下文懒汉式里面的同步方法解决线程问题Java多线程04—同步方法解决线程的安全问题


  • 什么是Singleton?

    • 在Java中指单例设计模式,它是软件开发中最常用的设计模式之一,单:唯一;例:实例
  • 单例设计模式:即某个类在整个系统中只能有一个实例对象可被获取和使用的代码模式
  • 例如:代表jvm运行环境的Runtime类

要点

一是某个类只能有一个实例

  • 构造器私有化

二是它必须自行创建这个实例

  • 含有一个该类的静态变量来保存这个唯一的实例

三是它必须自行向整个系统提供这个实例

  • 对外提供直接获取该实例对象的方式:

    • 直接暴露
    • 用静态变量的get方法获取

几种常见的方式

饿汉式

在类初始化时直接创建对象,不存在线程安全问题

直接实例化饿汉式(简洁直观)
/*
饿汉式:直接创建实例对象,不管是否需要这个对象,都会创建
(1):构造器私有化
(2):自行创建,并且用静态变量保存
(3):向外提供这个单例
(4):强调这是一个单例,我们可以用final修改
 */
public class Singleton01 {
    public static final Singleton01 INSTANCE = new Singleton01();
    private Singleton01() {
    }
}
枚举式(最简洁)
/*
枚举类型:表示该类型的对象是有限的几个,所以可以限定为一个,就成了单例
 */
public enum  Singleton02 {
    INSTANCE
}
静态代码块饿汉式(适合复杂实例化)
public class Singleton03 {
    public static final Singleton03 INSTANCE;
    static {
        INSTANCE=new Singleton03();
    }
    private Singleton03(){
    }
}
测试
/*
枚举类型打印出来的数据不一样,因为枚举是重写了toString方法,打印出来的是对象的名字
 */
public class TestSingleton {
    public static void main(String[] args) {
        Singleton01 instance1 = Singleton01.INSTANCE;
        System.out.println(instance1);//SingletonTest.Singleton01@6d6f6e28
        
        Singleton02 instance2 = Singleton02.INSTANCE;
        System.out.println(instance2);//INSTANCE
    }
}

懒汉式

延迟创建对象

线程不安全(适用于单线程)
/*
懒汉式:
延迟创建这个实例对象
1.构造器私有化
2.用一个静态变量保存这个唯一的实例
3.提供一个静态方法,获取这个实例对象
 */
public class Singleton04 {
    private static Singleton04 instance;
    private Singleton04(){
    }
    public static Singleton04 getInstance(){
        if(instance==null){
            instance=new Singleton04();
        }
        return instance;
    }
}

单线情况下测试:

public class TestSingleton02 {
    public static void main(String[] args) {
        //单线情况下
        Singleton04 singleton01=Singleton04.getInstance();
        Singleton04 singleton02=Singleton04.getInstance();
        //测试拿到的是不是同一个对象
        System.out.println(singleton01==singleton02);//true
    }
}
线程安全(适用于多线程)
  1. 可能不安全
import java.util.concurrent.*;

public class TestSingleton02 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //单线情况下
//        Singleton04 singleton01=Singleton04.getInstance();
//        Singleton04 singleton02=Singleton04.getInstance();
//        System.out.println(singleton01==singleton02);//true
        //线程安全问题
        Callable<Singleton04> c = new Callable<Singleton04>(){
            @Override
            public Singleton04 call() throws Exception {
                return Singleton04.getInstance();
            }
        };

        ExecutorService es = Executors.newFixedThreadPool(2);
        Future<Singleton04> f1 = es.submit(c);
        Future<Singleton04> f2 = es.submit(c);

        Singleton04 s1 = f1.get();
        Singleton04 s2 = f2.get();

        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s2==s1);
        //运行结果有概率问题,可能false可能true
        es.shutdown();
       
    }
}

解决办法:同步方法synchronized

类Singleton05

//学习内容:
//开发时间:10月30日  21:38
package SingletonTest02;
/*
懒汉式:
延迟创建这个实例对象
1.构造器私有化
2.用一个静态变量保存这个唯一的实例
3.提供一个静态方法,获取这个实例对象
 */
public class Singleton05 {
    private static Singleton05 instance;
    private Singleton05(){
    }
    public static Singleton05 getInstance(){
        synchronized (Singleton05.class){//当前类为锁对象
            if(instance==null){

                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                instance=new Singleton05();
            }
        }

        return instance;
    }
}

测试类:TestSingleton022


import java.util.concurrent.*;

public class TestSingleton022 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //单线情况下
//        Singleton04 singleton01=Singleton04.getInstance();
//        Singleton04 singleton02=Singleton04.getInstance();
//        System.out.println(singleton01==singleton02);//true
        //线程安全问题
        Callable<Singleton05> c = new Callable<Singleton05>(){
            @Override
            public Singleton05 call() throws Exception {
                return Singleton05.getInstance();
            }
        };

        ExecutorService es = Executors.newFixedThreadPool(2);
        Future<Singleton05> f1 = es.submit(c);
        Future<Singleton05> f2 = es.submit(c);

        Singleton05 s1 = f1.get();
        Singleton05 s2 = f2.get();

        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s2==s1);

        es.shutdown();

    }
}
静态内部类形式(适用于多线程)

既能保持延迟加载,还能保证线程安全(看注释)

/*
在内部类被加载和初始化时,才创建INSTANCE实例对象
静态内部类不会随着外部类的加载和初始化而初始化,它是要单独去加载和初始化
因为是在内部类加载和初始化时,创建的,因此是线程安全的
 */
public class Singleton07 {

    public Singleton07() {
    }

    private static class Inner{
        private static final Singleton07 INSTANCE=new Singleton07();
    }//内部类
    public static Singleton07 getInstance2(){
        return Inner.INSTANCE;
    }
}

目录
相关文章
|
1月前
|
设计模式 前端开发 JavaScript
JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式
本文深入探讨了JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式,结合电商网站案例,展示了设计模式如何提升代码的可维护性、扩展性和可读性,强调了其在前端开发中的重要性。
29 2
|
2月前
|
设计模式 缓存 Java
面试题:谈谈Spring用到了哪些设计模式?
面试题:谈谈Spring用到了哪些设计模式?
|
3月前
|
设计模式 安全 算法
【Java面试题汇总】设计模式篇(2023版)
谈谈你对设计模式的理解、七大原则、单例模式、工厂模式、代理模式、模板模式、观察者模式、JDK中用到的设计模式、Spring中用到的设计模式
|
3月前
|
设计模式 存储 安全
设计模式——设计模式介绍和单例设计模式
饿汉式(静态常量)、饿汉式(静态代码块)、懒汉式(线程不安全)、懒汉式(线程安全,同步方法)、懒汉式(线程不安全,同步代码块)、双重检查(推荐,线程安全、懒加载)、静态内部类(推荐)、枚举(推荐)
|
4月前
|
设计模式 JavaScript 前端开发
从工厂到单例再到策略:Vue.js高效应用JavaScript设计模式
【8月更文挑战第30天】在现代Web开发中,结合使用JavaScript设计模式与框架如Vue.js能显著提升代码质量和项目的可维护性。本文探讨了常见JavaScript设计模式及其在Vue.js中的应用。通过具体示例介绍了工厂模式、单例模式和策略模式的应用场景及其实现方法。例如,工厂模式通过`NavFactory`根据用户角色动态创建不同的导航栏组件;单例模式则通过全局事件总线`eventBus`实现跨组件通信;策略模式用于处理不同的表单验证规则。这些设计模式的应用不仅提高了代码的复用性和灵活性,还增强了Vue应用的整体质量。
65 1
|
4月前
|
设计模式 安全 图形学
Unity精华☀️ 面试官眼中的「设计模式」
Unity精华☀️ 面试官眼中的「设计模式」
|
4月前
|
设计模式 算法 Java
面试官:JDK中都用了哪些设计模式?
面试官:JDK中都用了哪些设计模式?
43 0
|
4月前
|
设计模式 Java
【Java】单例设计模式
【Java】单例设计模式
|
5月前
|
设计模式 存储 缓存
Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
63 0
|
5月前
|
设计模式 缓存 安全
Java面试题:设计模式在并发编程中的创新应用,Java内存管理与多线程工具类的综合应用,Java并发工具包与并发框架的创新应用
Java面试题:设计模式在并发编程中的创新应用,Java内存管理与多线程工具类的综合应用,Java并发工具包与并发框架的创新应用
45 0