【转载】Java设计模式---单例模式

转自

  1. https://blog.csdn.net/goodlixueyong/article/details/51935526
  2. https://www.runoob.com/design-pattern/singleton-pattern.html(还有多个案例可以参考)

注意

  • DCL 双检锁 volatile 关键字必须加上,因为有可能指令重排导致对象初始化两次。volatile为什么不能保证原子性?
  • 虚拟机只执行了分配空间,对象地址引用这两步,这是线程B过来发现对象已经被创建了,但是获取到的对象是还没有被初始化的。虽然锁住了,但是有可能会释放锁,这时候因为指令重排导致属性已经被指向对象地址,但是对象还未创建,判断就会错误认为这个对象已经创建,从而导致不安全的行为(来自B站评论,感觉这个比较正确)

代码

构造器要声明为私有的,防止被实例化

  1. 懒汉模式
package com.example.study.zerodispersal.singleton;
// 懒汉模式
public class Lazy {
    private static Lazy instance;
    // 如果编写的是多线程程序,则不要删除代码中的关键字synchronized,否则将存在线程非安全的问题。如果不删除这两个关键字就能保证线程安全,但是每次访问时都要同步,会影响性能,且消耗更多的资源,这是懒汉式单例的缺点。
    public static synchronized Lazy getInstance(){
        if(instance == null){
            System.out.println("Singleton 对象未创建,开始创建");
            instance = new Lazy();
        }else{
            System.out.println("Singleton 对象已经创建");
        }
        return instance;
    }

    public static void main(String[] args) {
        Lazy.getInstance();
        Lazy.getInstance();
        Lazy.getInstance();
    }
}

  1. 饿汉式模式
package com.example.study.zerodispersal.singleton;
// 饿汉式
public class HungryMan {
    // 饿汉式单例在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以是线程安全的,可以直接用于多线程而不会出现问题。
    private static HungryMan instance = new HungryMan();
    public static HungryMan getInstance(){
        return instance;
    }

    public static void main(String[] args) {
        HungryMan.getInstance();
        HungryMan.getInstance();
        HungryMan.getInstance();
    }

}

  1. 双重校验模式
package com.example.study.zerodispersal.singleton;
// 双重校验式
public class DoubleCheck {
    private static volatile DoubleCheck instance;
    public static  DoubleCheck getInstance(){
        // 将方法的synchronized关键字取消,防止每次都同步导致等待
        if(instance == null){
            // 同步代码块中准备创建对象
            synchronized(DoubleCheck.class){
                // 假如两个线程A、B,A执行了if (instance == null)语句,它会认为单例对象没有创建,此时线程切到B也执行了同样的语句,B也认为单例对象没有创建,然后两个线程依次执行同步代码块,并分别创建了一个单例对象。为了解决这个问题
                if (instance == null) {
                    instance = new DoubleCheck();
                }
            }
        }
        return instance;
    }

    public static void main(String[] args) {
        DoubleCheck.getInstance();
        DoubleCheck.getInstance();
        DoubleCheck.getInstance();
    }
}

posted @   夏秋初  阅读(17)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
点击右上角即可分享
微信分享提示