java单例模式

本文详细介绍了Java中的单例设计模式,包括饿汉式和懒汉式的不同实现方式,并通过代码示例展示了它们的线程安全性和实例化过程。枚举类型在实现单例时能确保线程安全,而懒汉式则分为线程不安全、线程安全及静态内部类三种实现。
摘要由CSDN通过智能技术生成

单例模式

单例模式是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
ps:博客有多种实现,内容较长,对代码有兴趣的可以上git:git地址,客官开心的话可以点赞

要点

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

常见形式

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

代码加注释深入理解

饿汉式1实现

/**
 * @author 小鱼
 * @version 1.0
 * @date 2021/8/14 11:21 上午
 * 饿汉式:直接创建对象,不存在线程安全问题
 *      方式1.直接实现实例化对象,最明确
 *          实现步骤:
 *              1.创建一个静态的常量的类对象
 *              2.构造器私有化,不允许外部创建
 */
public class SingletonHungryOne {
    public static final SingletonHungryOne INSTANCE=new SingletonHungryOne();

    private SingletonHungryOne(){
    }
}

验证

/**
 * @author 小鱼
 * @version 1.0
 * @date 2021/8/14 11:31 上午
 * 测试饿汉式1是否正确
 */
public class TestOne {
    public static void main(String[] args) {
        SingletonHungryOne s1=SingletonHungryOne.INSTANCE;
        SingletonHungryOne s2=SingletonHungryOne.INSTANCE;
        System.out.println(s1.equals(s2));
        System.out.println(s1==s2);
        //判断对象hashCode是否相等
        System.out.println("s1对象hashCode:   "+s1.hashCode());
        System.out.println("s2对象hashCode:   "+s2.hashCode());
    }
}

在这里插入图片描述

饿汉式2实现

使用枚举的特性创建单例

/**
 * @author 小鱼
 * @version 1.0
 * @date 2021/8/14 12:00 下午
 * 饿汉式:
 *      方式2:使用枚举类型创建:
 *          因为枚举类型表示该类型的对象是有限的几个,我们可以限定一个,那么就成了单例了
 *          让JVM来帮我们保证线程安全和单一实例的问题。
 * 我们只需要在类里面第一行添加INSTANCE;就实现了单例了
 */
public enum SingletonHungryTwo {
    INSTANCE;

    public void doSomething() {
        System.out.println("doSomething");
    }
}

验证

/**
 * @author 小鱼
 * @version 1.0
 * @date 2021/8/14 11:31 上午
 * 测试饿汉式2是否正确
 */
public class TestTwo {
    public static void main(String[] args) {
        SingletonHungryTwo s1=SingletonHungryTwo.INSTANCE;
        SingletonHungryTwo s2=SingletonHungryTwo.INSTANCE;
        System.out.println(s1.equals(s2));
        System.out.println(s1==s2);
        //判断对象hashCode是否相等
        System.out.println("s1对象hashCode:   "+s1.hashCode());
        System.out.println("s2对象hashCode:   "+s2.hashCode());
        s1.doSomething();
        s2.doSomething();
    }
}

在这里插入图片描述

懒汉式1实现

线程不安全

/**
 * @author 小鱼
 * @version 1.0
 * @date 2021/8/14 12:13 下午
 * 懒汉式:
 *      方式1:线程不安全
 *          1.构造器私有化
 *          2.用一个静态变量保存这个唯一实例
 *          3.提供一个静态方法获取这个唯一实例
 */
public class SingletonLazyOne {
    private SingletonLazyOne(){

    }
    private static SingletonLazyOne singletonLazyOne;
    public static SingletonLazyOne getInstance(){
        if(singletonLazyOne==null){
            return singletonLazyOne= new SingletonLazyOne();
        }
        return singletonLazyOne;
    }
}

验证

/**
 * @author 小鱼
 * @version 1.0
 * @date 2021/8/14 11:31 上午
 * 测试懒汉式1是否正确
 */
public class TestLazyOne {
    public static void main(String[] args) {
        SingletonLazyOne s1=SingletonLazyOne.getInstance();
        SingletonLazyOne s2=SingletonLazyOne.getInstance();
        System.out.println(s1.equals(s2));
        System.out.println(s1==s2);
        //判断对象hashCode是否相等
        System.out.println("s1对象hashCode:   "+s1.hashCode());
        System.out.println("s2对象hashCode:   "+s2.hashCode());
    }
}

懒汉式2实现

线程安全单例,但是可以通过反射和反序列化进行内部破坏

/**
 * @author 小鱼
 * @version 1.0
 * @date 2021/8/14 12:13 下午
 * 懒汉式:
 *      方式2:线程安全
 *          1.构造器私有化
 *          2.用一个静态变量保存这个唯一实例(为了防止指令重排,我们加入了volatile关键字)
 *          3.提供一个对外创建对象的安全的静态方法
 *
 */
public class SingletonLazyTwo {
    private SingletonLazyTwo(){

    }
    private static volatile SingletonLazyTwo singletonLazyTwo;
    public static SingletonLazyTwo getInstance(){
        if(singletonLazyTwo==null){
            synchronized (SingletonLazyTwo.class){
                if(singletonLazyTwo==null){
                    return singletonLazyTwo= new SingletonLazyTwo();
                }
            }
        }
        return singletonLazyTwo;
    }
}

验证

/**
 * @author 小鱼
 * @version 1.0
 * @date 2021/8/14 11:31 上午
 * 测试懒汉式2是否正确
 */
public class TestLazyTwo {
    public static void main(String[] args) {
        SingletonLazyTwo s1=SingletonLazyTwo.getInstance();
        SingletonLazyTwo s2=SingletonLazyTwo.getInstance();
        System.out.println(s1.equals(s2));
        System.out.println(s1==s2);
        //判断对象hashCode是否相等
        System.out.println("s1对象hashCode:   "+s1.hashCode());
        System.out.println("s2对象hashCode:   "+s2.hashCode());
    }
}

懒汉式3

静态内部类的形式:线程安全

/**
 * @author 小鱼
 * @version 1.0
 * @date 2021/8/14 12:13 下午
 * 懒汉式:
 *      方式3:
 *      在内部类被加载和初始化时,才创建INSTANCE实例对象
 *      静态内部类不会自动随着外部类的加载和初始化而初始化,它是要单独去加载和初始化的。
 *
 */
public class SingletonLazyThree {
    private SingletonLazyThree(){

    }
    public static SingletonLazyThree getInstance(){
       return  Instance.instance;
    }
    private  static class Instance{
        private static final SingletonLazyThree instance=new SingletonLazyThree();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值