单例设计模式

本文详细介绍了Java中的单例模式,包括懒汉式实现、存在的多线程问题以及解决办法——双重检查锁定。通过实例代码展示了如何确保在多线程环境下正确地创建并访问单例对象,并讨论了单例模式在系统环境信息、数据库连接池等场景的应用。此外,还提出了与单例模式相关的面试问题,如Spring中单例的维持、ServletContext和ApplicationContext的性质等。
摘要由CSDN通过智能技术生成

单例模式

一个单一的类,负责创建自己的对象,同时确保系统中只有单个对象被创建。

单例特点

  • 某个类只能有一个实例(构造器私有)
  • 它必须自行创建这个实例(自己编写实例化逻辑)
  • 它必须自行向整个系统提供这个实例(对外提供实例化方法)

在这里插入图片描述

懒汉式

package com.xx.design.creatation.singleton;


public class Person {
    private String name;
    private String age;

    // 懒汉:没有再去创建
    private static Person instance;

   	// 饿汉式
    // private final static Person instance = new Person();

    // 构造器私有,外部不能实例化
    private Person(){
        System.out.println("创建了Person对象");
    }

    // 提供给外部的方法
    public static Person getInstance(){

        // 如果没有实例再去创建
        if(instance == null){
             Person person = new Person();
             instance = person;
        }
        return instance;
    }
}

package com.xx.design.creatation.singleton;

// 测试函数
public class MainTest {

   public static void main(String[] args) {

       Person person1 = Person.getInstance();

       Person person2 = Person.getInstance();

       System.out.println(person1 == person2);

       /*
           创建了Person对象
           true
       */
   }
}

多线程存在问题

public static Person getInstance(){

    // 如果多线程的情况下,多个人一起进入这个方法,同时进入if
    // 同时判断是null , 那么大家会同时去创建对象,所以存在问题
    if(instance == null){
         Person person = new Person();
         instance = person;
    }
    return instance;
}


// 方法一:加锁(锁方法)
// getInstance方法也是一个static方法,所以是加在类上面,创建对象用的是同一个类,所以会锁住
public static synchronized Person getInstance(){
    if(instance == null){
         Person person = new Person();
         instance = person;
    }
    return instance;
}


// 方法二:加锁(锁代码块),区别不大
    public static Person getInstance(){
        synchronized (Person.class){
            if(instance == null){
                Person person = new Person();
                instance = person;
            }
        }
        return instance;
    }

双重检查


 public static Person getInstance() {
 	// 如果对象为空,再加锁,再来创建对象
 	// 可以发现同样存在多个线程一起进来,都判断对象为空,创建多个对象
     if (instance == null) {
         synchronized (Person.class) {
             Person person = new Person();
             instance = person;
         }
     }
     return instance;
 }



//再加一次判断

 public static Person getInstance() {

    if (instance == null) {
        synchronized (Person.class) {
        	// 前面一个人进来,创建对象,第二个人就可以不用创建对象
            if(instance == null){
            	// 但是依然存在问题
            	// 因为赋值操作,会被封装成先创建对象,然后分配地址等等
            	// 所以需要用 volatile 关键字修饰
                Person person = new Person();
                instance = person;
            }
        }
    }
    return instance;
}

应用场景

  • 多线程中的线程池
  • 数据库的连接池
  • 系统环境信息
  • 上下文(ServletContext)

面试问题

  • 系统环境信息(System.getProperties())?
  • Spring中怎么保持组件单例的
  • SerletContext是什么,是单例吗,怎么保证
  • ApplicationContext是什么,是单例吗,怎么保证
    • tomcat:一个应用(部署的一个war包)会有一个应用上下文
    • spring:表示整个IOC容器(单例),ioc容器中有很多组件(单例)
  • 数据库连接池怎么创建出来,保证单例的
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值