首页 > 其他分享 >设计模式—单例模式

设计模式—单例模式

时间:2023-12-12 10:47:54浏览次数:29  
标签:Singleton String value instance static 模式 单例 设计模式 public

本文是关于设计模式中单例模式的 Java 代码实现详解

懒汉式

public final class Singleton {
    private static Singleton instance;
    public String value;

    private Singleton(String value) {
        this.value = value;
    }

    public static Singleton getInstance(String value) {
        if (instance == null) {
            instance = new Singleton(value);
        }
        return instance;
    }
}

测试代码

class test{
    public static void main(String[] args) {
        Singleton singleton = Singleton.getInstance("FOO");
        Singleton another = Singleton.getInstance("BAR");

        System.out.println(singleton.value);
        System.out.println(another.value);
    }
}

输出

image

但是这种方法在多线程的使用场景下是不安全的,有可能会产生多个单例实例,比如把测试代码改成下面的形式

class test {
    static class ThreadFoo implements Runnable {
        @Override
        public void run() {
            Singleton singleton = Singleton.getInstance("FOO");
            System.out.println(singleton.value);
            System.out.println("In Foo, " + singleton);
        }
    }

    static class ThreadBar implements Runnable {
        @Override
        public void run() {
            Singleton singleton = Singleton.getInstance("Bar");
            System.out.println(singleton.value);
            System.out.println("In Bar, " + singleton);
        }
    }

    public static void main(String[] args) {
        Thread threadFoo = new Thread(new ThreadFoo());
        Thread threadBar = new Thread(new ThreadBar());

        threadFoo.start();
        threadBar.start();
    }
}

运行结果就会发生变化

image

饿汉式

多线程场景下安全使用单例模式的一种方法是饿汉式

public class Singleton {
	// 在类加载的时候就创建并初始化
    private static Singleton instance = new Singleton("harry");
    public String value;

    private Singleton(String value) {
        this.value = value;
    }

    public static Singleton getInstance(String value) {
        if (instance == null) {
            instance = new Singleton(value);
        }
        return instance;
    }
}

测试代码不变,运行结果如下

image

可以看到,两个实例的 hashcode 是相同的,是同一个对象。但是使用这种方法需要在类加载的时候就初始化实例,占用内存资源,不推荐使用这种方法。

双重检测

双重检测是目前常用的线程安全单例模式的方式,它有两点改变:

  • 在实例上加关键字 volatile ,防止指令重排序,因为指令重排序可能会导致 Singleton 对象被 new 出来,并且赋值给 instance 之后,还没来得及初始化,就被另一个线程使用了
  • getInstance 方法中对创建实例的代码加锁,保证只有一个线程能创建示例
public class Singleton {
    // 加入 volatile 关键字防止指令重排
    private static volatile Singleton instance;
    public String value;

    private Singleton(String value){
        this.value = value;
    }

    public static synchronized Singleton getInstance(String value){
        if(instance == null){
            // 加类级别的锁
            synchronized(Singleton.class){
                // 避免多线程并发时多次创建对象
                if(instance == null){
                    instance = new Singleton(value);
                }
            }
        }
        return instance;
    }
}

测试代码不变,运行结果如下

image

静态内部类

用静态内部类的方式实现单例类,利用了Java 静态内部类的特性

Java 加载外部类的时候,不会创建内部类的实例,只有在外部类使用到内部类的时候才会创建内部类实例

SingletonInner 是一个静态内部类,当外部类 Singleton 被加载的时候,并不会创建 SingletonInner 实例对象。

只有当调用 getInstance 方法时,SingletonInner 才会被加载,这个时候才会创建 instanceinstance 的唯一性、创建过程的线程安全性,都由 JVM 来保证。

public class Singleton {
    public String value;

    private Singleton(String value) {
        this.value = value;
    }

    private static class SingletonInner {
        private static final Singleton instance = new Singleton("harry");
    }

    public static synchronized Singleton getInstance(String value) {
        return SingletonInner.instance;
    }
}

测试代码不变,运行结果如下

image

枚举

标签:Singleton,String,value,instance,static,模式,单例,设计模式,public
From: https://www.cnblogs.com/shixuanliu/p/17896159.html

相关文章

  • Java单例模式
    代码publicclassSamlUtil{privatestaticSamlUtilsamlUtil; privatestaticfinalObjectlock=newObject();privateSamlUtil(){ } publicstaticSamlUtilgetInstance(){ SamlUtiltemp=samlUtil; if(temp==null){ synchronized......
  • 内核模式
    内核模式Microsoft-用户模式和内核模式内核模式可以干什么用OpenArk查看Windows下所有快捷键的归属。WindowsDefender一般会要求用户打开内核隔离(MemoryIntegrity)。根据微软的描述:“如果内核模式驱动程序意外写入错误的虚拟地址,则属于操作系统或其他驱动程序的数......
  • 建造者模式
    建造者模式故名思意有两个重要的原色,一个是产品(product),即我们需要的某个目标类的对象,一个建造者(builder),当然你可以把建造者先抽象出一个的abstractbuilder,再继承一个具体的builder.最妙的一句是builder类再builder具体东西时,returnthis,这样在builder对象时,就可以使用User......
  • 23种设计模式——装饰者模式
    今天给大家说一下23种设计模式中装饰者模式。一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。这个时候,我们就需要用到装饰者模式了,它可以实现在不增加很多子类的情况下扩展类的功能。概念:装饰者模式(DecoratorPatt......
  • 工厂模式
    工厂模式可分为简单工程、工厂方法、抽象工厂三类:简单工厂模式:又叫做静态工厂方法模式。该模式是通过传⼊参数来返回相应的类,这种方式比较单一,一个工厂负责制造所有子类产品,当增加一个子类产品时,需要对工厂进行修改,扩展性相对较差。简单工厂模式看为工厂方法模式的一种特例,两者......
  • 模板模式
    1#include<iostream>2usingnamespacestd;34//PC机,手机,平板5classMakeOrder{6public:7//virtualvoidstartOrder()=0;第一版8//钩子函数的模板方法9virtualvoidstartOrder(){10cout<<"下订单了"<<endl......
  • 设计模式之责任链模式
    1.定义请求沿着一条链传递,直到有一个对象能够处理它为止2.口语化表述假设某公司的财务审批流程如下:项目经理可以审批1000元以下的费用,大于1000元的费用提交给部门经理审批部门经理可以审批10000元以下的费用,大于10000的费用提交给总经理审批总经理可以审批任何额度的费用......
  • 抽象工厂模式:角色解析与应用探索
    前言工厂模式一般指的是简单工厂模式、工厂方法模式、抽象工厂模式,这是三种工厂模式的最后一篇,其他两种的文章链接如下:设计模式之是简单工厂模式_凡夫编程的技术博客_51CTO博客工厂方法模式:改变你对软件开发的认知_凡夫编程的技术博客_51CTO博客建议三种模式放在一起对比学习,更能......
  • oracle Parallel模式-Parallel用法(/*+PARALLEL(n)*/)
    一、用途强行启用并行度来执行当前SQL。这个在Oracle9i之后的版本可以使用,之前的版本现在没有环境进行测试。也就是说,加上这个说明,可以强行启用Oracle的多线程处理功能。举例的话,就像电脑装了多核的CPU,但大多情况下都不会完全多核同时启用(2核以上的比较明显),使用parallel说明,就会......
  • 设计模式-访问者模式(主要理解“双重分派”)
    代码展示:packagecom.example.test;importjava.util.ArrayList;importjava.util.List;publicclass访问者模式{}abstractclassDepartment{abstractvoidvisit(FullTimeEmployeefullTimeEmployee);//正式工的访问abstractvoidvisit(PartTimeEmployee......