第一季:2单例设计模式【Java面试题】

简介: 第一季:2单例设计模式【Java面试题】

前言


2022 9/29 22:59

路漫漫其修远兮,吾将上下而求索


本文是根据尚硅谷学习所做笔记

仅供学习交流使用,转载注明出处

推荐

【尚硅谷经典Java面试题第一季(java面试精讲)-哔哩哔哩】

尚硅谷经典Java面试题一二三季

尚硅谷经典Java面试题(第1季)

第一季:2单例设计模式

推荐:

单例模式【Java设计模式】

设计模式【java提高】

题目

编程题:写一个Singleton实例

什么是Singleton ?

  • Singleton:在Java中即指单例设计模式,它是软件开发中最常用的设计模式之一
  • 单:唯一
  • 例:实例

    单例设计模式,即某个类在整个系统中只能有一个实例对象可被获取和使用的代码模式。
  • 例如:代表JVM运行环境的RunTime类

要点

  • 一是某个类只能有一个实例;
    ◆构造器私有化
  • 二是它必须自行创建这个实例;
    ◆含有一个该类的静态变量来保存这个唯一的实例
  • 三是它必须自行向整个系统提供这个实例;
    ◆对外提供获取该实例对象的方式:
    (1)直接暴露(2)用静态变量的get方法获取


几种常见形式

  • 饿汉式∶直接创建对象,不存在线程安全问题
  • 直接实例化饿汉式(简洁直观)
  • 枚举式(最简洁)
  • 静态代码块饿汉式(适合复杂实例化)
  • 懒汉式:延迟创建对象
  • 线程不安全(适用于单线程)
  • 线程安全(适用于多线程)
  • 静态内部类形式(适用于多线程)


实现

饿汉式

直接实例化饿汉式(简洁直观)

package singleton2;
/**
 * 饿汉式
 *  直接创建实例对象,不管你是否需要对象都会创建
 * (1)构造器私有化
 * (2)自行创建,并且用静态变量保存
 * (3)向外提供这个实例
 * (4)强调这是个单例,我们可以使用final修改
 */
public class Singleton1 {
    public static final Singleton1 INSTANCE=new Singleton1();
    private Singleton1(){
    }
}

枚举式(最简洁)

package singleton2;
/**
 * 枚举类型,表示给类型的对象是有限的几个
 * 我们可以限定为一个,就成为了单例了
 */
public enum Singleton2 {
    INSTANCE
}

静态代码块饿汉式(适合复杂实例化)

package singleton2;
import java.io.IOException;
import java.util.Properties;
public class Singleton3 {
    public static final Singleton3 INSTANCE;
    private String info;
    static {
        try {
            Properties pro=new Properties();
            //用类加载器加载src下的配置文件
            pro.load(Singleton3.class.getClassLoader().getResourceAsStream("single.properties"));
            INSTANCE=new Singleton3(pro.getProperty("info"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    private Singleton3(String info){
        this.info=info;
    }
    public String getInfo() {
        return info;
    }
    public void setInfo(String info) {
        this.info = info;
    }
    @Override
    public String toString() {
        return "Singleton3{" +
                "info='" + info + '\'' +
                '}';
    }
}

single.properties

#key=value
info=atguigu

测试

package singleton2;
import org.junit.Test;
public class TestSingletonEHan {
    @Test
    public void testSingleton1(){
        Singleton1 s=Singleton1.INSTANCE;
        System.out.println(s);//singleton2.Singleton1@1b9e1916
    }
    @Test
    public void testSingleton2(){
        Singleton2 s=Singleton2.INSTANCE;
        System.out.println(s);//INSTANCE
    }
    @Test
    public void testSingleton3(){
        Singleton3 s=Singleton3.INSTANCE;
        System.out.println(s);//Singleton3{info='atguigu'}
    }
}

懒汉式

线程不安全(适用于单线程)

package singleton2;
/**
 * 懒汉式
 *
 * (1)构造器私有化
 * (2)用一个静态变量保存这个唯一的实例
 * (3)提供一个静态方法,获取这个实例对象
 *
 */
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;
    }
}

线程安全(适用于多线程)

package singleton2;
/**
 * 懒汉式
 *
 * (1)构造器私有化
 * (2)用一个静态变量保存这个唯一的实例
 * (3)提供一个静态方法,获取这个实例对象
 *
 */
public class Singleton5 {
    private volatile static Singleton5 instance;
    private Singleton5(){
    }
    public static Singleton5 getInstance(){
        if (instance==null) {
            synchronized (Singleton5.class) {
                if (instance==null){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    instance=new Singleton5();
                }
            }
        }
        return instance;
    }
}

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

package singleton2;
/**
 * 在内部类被加载和初始化时,才创建INSTANCE
 * 静态类不会自动随着外部类的加载和初始化而初始化的,它是要单独去加载和初始化的。
 * 因为是在内部类加载和初始化时,创建的,因此是线程安全的
 */
public class Singleton6 {
    private Singleton6(){
    }
    private static class Inner{
        private static final Singleton6 INSTANCE =new Singleton6();
    }
    public static Singleton6 getInstance(){
        return Inner.INSTANCE;
    }
}

测试

package singleton2;
import org.junit.Test;
import java.util.concurrent.*;
public class TestSingletonLanHan {
    @Test
    public void testSingleton4() throws ExecutionException, InterruptedException {
        /*
        Singleton4 s1=Singleton4.getInstance();
        Singleton4 s2=Singleton4.getInstance();
        System.out.println(s1==s2);//true
        System.out.println(s1);//singleton2.Singleton4@1b9e1916
        System.out.println(s2);//singleton2.Singleton4@1b9e1916
        */
        Callable<Singleton4> c=new Callable<Singleton4>() {
            @Override
            public Singleton4 call() throws Exception {
                return Singleton4.getInstance();
            }
        };
        ExecutorService es= Executors.newFixedThreadPool(2);
        Future<Singleton4> f1 = es.submit(c);
        Future<Singleton4> f2 = es.submit(c);
        Singleton4 s1 = f1.get();
        Singleton4 s2 = f2.get();
        System.out.println(s1==s2);//false
        System.out.println(s1);//singleton2.Singleton4@3b764bce
        System.out.println(s2);//singleton2.Singleton4@759ebb3d
        es.shutdown();
    }
    @Test
    public void testSingleton5() throws ExecutionException, InterruptedException {
        Callable<Singleton5> c=new Callable<Singleton5>() {
            @Override
            public Singleton5 call() throws Exception {
                return Singleton5.getInstance();
            }
        };
        ExecutorService es= Executors.newFixedThreadPool(2);
        Future<Singleton5> f1 = es.submit(c);
        Future<Singleton5> f2 = es.submit(c);
        Singleton5 s1 = f1.get();
        Singleton5 s2 = f2.get();
        System.out.println(s1==s2);//true
        System.out.println(s1);//singleton2.Singleton5@3b764bce
        System.out.println(s2);//singleton2.Singleton5@3b764bce
        es.shutdown();
    }
    @Test
    public void testSingleton6(){
        Singleton6 s=Singleton6.getInstance();
        System.out.println(s);//singleton2.Singleton6@1b9e1916
    }
}

最后


2022 9/29 23:49


p2


Markdown 5062 字数 364 行数

HTML 4532 字数 249 段落


相关文章
|
15天前
|
设计模式 算法 Java
Java中的设计模式:提升代码质量的秘诀
【8月更文挑战第23天】在Java开发中,设计模式是提高代码可读性、可维护性和扩展性的强有力工具。本文通过浅显易懂的语言和实际案例,探讨几种常见的设计模式及其在Java中的应用,旨在帮助开发者更好地理解并运用这些模式来优化自己的代码结构。
35 2
|
17天前
|
Java
【Java集合类面试二十八】、说一说TreeSet和HashSet的区别
HashSet基于哈希表实现,无序且可以有一个null元素;TreeSet基于红黑树实现,支持排序,不允许null元素。
|
8天前
|
设计模式 缓存 算法
揭秘策略模式:如何用Java设计模式轻松切换算法?
【8月更文挑战第30天】设计模式是解决软件开发中特定问题的可重用方案。其中,策略模式是一种常用的行为型模式,允许在运行时选择算法行为。它通过定义一系列可互换的算法来封装具体的实现,使算法的变化与客户端分离。例如,在电商系统中,可以通过定义 `DiscountStrategy` 接口和多种折扣策略类(如 `FidelityDiscount`、`BulkDiscount` 和 `NoDiscount`),在运行时动态切换不同的折扣逻辑。这样,`ShoppingCart` 类无需关心具体折扣计算细节,只需设置不同的策略即可实现灵活的价格计算,符合开闭原则并提高代码的可维护性和扩展性。
23 2
|
8天前
|
设计模式 Java
Java 设计模式之谜:工厂模式与抽象工厂模式究竟隐藏着怎样的神奇力量?
【8月更文挑战第30天】在Java编程中,设计模式为常见问题提供了高效解决方案。工厂模式与抽象工厂模式是常用的对象创建型设计模式,能显著提升代码的灵活性、可维护性和可扩展性。工厂模式通过定义创建对象的接口让子类决定实例化哪个类;而抽象工厂模式则进一步提供了一个创建一系列相关或相互依赖对象的接口,无需指定具体类。这种方式使得系统更易于扩展和维护。
18 1
|
8天前
|
设计模式 Java
重构你的代码:探索Java中的混合、装饰器与组合设计模式
【8月更文挑战第30天】在软件开发中,设计模式为特定问题提供了结构化的解决方案,使代码更易理解、维护及扩展。本文将介绍三种常用的 Java 设计模式:混合模式、装饰器模式与组合模式,并附有示例代码展示实际应用。混合模式允许通过继承多个接口或抽象类实现多重继承;装饰器模式可在不改变对象结构的情况下动态添加新功能;组合模式则通过树形结构表示部分-整体层次,确保客户端处理单个对象与组合对象时具有一致性。
|
17天前
|
消息中间件 缓存 算法
Java多线程面试题总结(上)
进程和线程是操作系统管理程序执行的基本单位,二者有明显区别: 1. **定义与基本单位**:进程是资源分配的基本单位,拥有独立的内存空间;线程是调度和执行的基本单位,共享所属进程的资源。 2. **独立性与资源共享**:进程间相互独立,通信需显式机制;线程共享进程资源,通信更直接快捷。 3. **管理与调度**:进程管理复杂,线程管理更灵活。 4. **并发与并行**:进程并发执行,提高资源利用率;线程不仅并发还能并行执行,提升执行效率。 5. **健壮性**:进程更健壮,一个进程崩溃不影响其他进程;线程崩溃可能导致整个进程崩溃。
23 2
|
17天前
|
存储 Java
【Java集合类面试二十九】、说一说HashSet的底层结构
HashSet的底层结构是基于HashMap实现的,使用一个初始容量为16和负载因子为0.75的HashMap,其中HashSet元素作为HashMap的key,而value是一个静态的PRESENT对象。
|
17天前
|
存储 Java
Java面向对象面试题总结(上)
在Java中,重写(Override)与重载(Overload)是两个重要的概念,关联到方法的定义与调用。重写是指子类对继承自父类的方法进行新的实现,以便提供子类特有的行为,其关键在于方法签名一致但方法体不同。重载则允许在同一个类中定义多个同名方法,只要参数列表不同即可,以此提供方法调用的灵活性。重写关注多态性,而重载强调编译时多态。
15 1
|
17天前
|
Java
【Java集合类面试三十】、BlockingQueue中有哪些方法,为什么这样设计?
BlockingQueue设计了四组不同行为方式的方法用于插入、移除和检查元素,以适应不同的业务场景,包括抛异常、返回特定值、阻塞等待和超时等待,以实现高效的线程间通信。
|
17天前
|
NoSQL Java 数据库
2022年整理最详细的java面试题、掌握这一套八股文、面试基础不成问题[吐血整理、纯手撸]
这篇文章是一份详尽的Java面试题总结,涵盖了从面向对象基础到分布式系统设计的多个知识点,适合用来准备Java技术面试。
2022年整理最详细的java面试题、掌握这一套八股文、面试基础不成问题[吐血整理、纯手撸]
下一篇
DDNS