单例模式总结

单例模式

所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类

只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。

单例模式有八种方式:

1) 饿汉式(静态常量)

2) 饿汉式(静态代码块)

  1. 懒汉式(线程不安全)

  2. 懒汉式(线程安全,同步方法)

  3. 懒汉式(线程安全,同步代码块)

6) 双重检查

7) 静态内部类

8) 枚举

饿汉式(线程安全)

饿汉式(静态常量)应用实例

步骤如下

  1. 构造器私有化 (防止 new )

  2. 类的内部创建对象

  3. 向外暴露一个静态的公共方法。getInstance

  4. 代码实现

class HungrySingleton{
    //构造函数私有化,防止直接new
    private HungrySingleton(){};
    //内部创建一个HungrySingleton的实例
    private static HungrySingleton instance = new HungrySingleton();
    //提供一个public 的静态方法,可以返回实例
    public static HungrySingleton getInstance(){
        return instance;
    }
}

优缺点

优点:写法简单,类装载的时候就完成了实例化,避免了线程同步的问题

缺点: 在类装载的时候就完成了实例化,没有达到Lazy Loading的效果,如果没用过这个实例,会造成内存的浪费

这种方式基于classloder机制避免了多线程的同步问题,不过,instance在类装载时就实例化,在单例模式中大多数都是调用getInstance方法, 但是导致类装载 的原因有很多种,因此不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化instance就没有达到lazy loading的效果

结论:这种单例模式可用可能造成内存浪费

饿汉式 通过反射或者序列化会破坏单例

懒汉式(线程不安全)

class Singleton{
    //初始化成员变量
    private static Sngleton singlenton;
    //私有化构造函数
    private Singleton(){}
    //判断是否有singleton
    public static Singleton getInstance(){
        if(singlenton ==null){
            singlenton = new Singleton();
        }
        return singlenton;
    }
}

优缺点说明

  1. 起到了Lazy Loading的效果,但是只能在单线程下使用。

  2. 如果在多线程下,一个线程进入了if (singleton == null)判断语句块,还未来得及

往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。所以

在多线程环境下不可使用这种方式

  1. 结论:在实际开发中,不要使用这种方式.

懒汉式(线程安全,synchornized方法)

class Singleton{
    //初始化成员变量
    private static Sngleton singlenton;
    //私有化构造函数
    private Singleton(){}
    //加入同步代码,解决线程不安全的问题
    public static synchronized Singleton getInstance(){
        if(singlenton ==null){
            singlenton = new Singleton();
        }
        return singlenton;
    }
}

优缺点说明

  1. 解决了线程不安全问题

  2. 效率太低了,每个线程在想获得类的实例时候,执行getInstance()方法都要进行

同步。而其实这个方法只执行一次实例化代码就够了,后面的想获得该类实例,

直接return就行了。方法进行同步效率太低

  1. 结论:在实际开发中,不推荐使用这种方式

双重检查

class Singleton{
    //初始化成员变量
    private static Sngleton singlenton;
    //私有化构造函数
    private Singleton(){}
    //双重判断
    public static Singleton getInstance(){
        if(singlenton == null){
            synchronized(Singleton.class){
                if(singlenton ==null){
                    singlenton = new Singleton();
                }
            }
        }
        return singlenton;
    }
    
}

优缺点说明

  1. Double-Check概念是多线程开发中常使用到的,如代码中所示,我们进行了两

次if (singleton == null)检查,这样就可以保证线程安全了。

  1. 这样,实例化代码只用执行一次,后面再次访问时,判断if (singleton == null),

直接return实例化对象,也避免的反复进行方法同步.

  1. 线程安全;延迟加载;效率较高

  2. 结论:在实际开发中,推荐使用这种单例设计模式

为什么一个if不行: 假如一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行,

另一个线程也通过了这个判断语句,这时便会产生多个实例

静态内部类

class Singleton{
    private Singleton(){}
    
    private static class SingletonInstance{
        private static final Singleton instance = new Singleton():
    }
    
    public static Singleton getInstance(){
        return SingletonInstance.instance;
    }
}

优缺点说明

  1. 这种方式采用了类装载的机制来保证初始化实例时只有一个线程。

  2. 静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化

时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的

实例化。

  1. 类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们

保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。

  1. 优点:避免了线程不安全,利用静态内部类特点实现延迟加载,效率高

  2. 结论:推荐使用.

枚举

enum Singleton{
    INSTANCE;
    public void method(){}
}
public enum Singleton {

    INSTANCE;

    private String objName;


    public String getObjName() {
        return objName;
    }


    public void setObjName(String objName) {
        this.objName = objName;
    }


    public static void main(String[] args) {

        // 单例测试
        Singleton firstSingleton = Singleton.INSTANCE;
        firstSingleton.setObjName("firstName");
        System.out.println(firstSingleton.getObjName());
        Singleton secondSingleton = Singleton.INSTANCE;
        secondSingleton.setObjName("secondName");
        System.out.println(firstSingleton.getObjName());
        System.out.println(secondSingleton.getObjName());

        // 反射获取实例测试
        try {
            Singleton[] enumConstants = Singleton.class.getEnumConstants();
            for (Singleton enumConstant : enumConstants) {
                System.out.println(enumConstant.getObjName());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
firstName
secondName
secondName
secondName

该实现可以防止反射攻击。在其它实现中,通过 setAccessible() 方法可以将私有构造函数的访问级别设置为 public,然后调用构造函数从而实例化对象,如果要防止这种攻击,需要在构造函数中添加防止多次实例化的代码。该实现是由 JVM 保证只会实例化一次,因此不会出现上述的反射攻击。

该实现在多次序列化和序列化之后,不会得到多个实例。而其它实现需要使用 transient 修饰所有字段,并且实现序列化和反序列化的方法。

资源下载链接为: https://pan.quark.cn/s/1bfadf00ae14 在 Linux 系统中,查找域名或主机名对应的 IP 地址是网络管理中的一项基础且关键任务,对于排查网络故障、调试网络问题以及监控网络服务是否正常运行等场景都非常重要。本文将介绍五种在 Linux 终端查询域名 IP 地址的方法。 首先,dig 命令(全称 Domain Information Groper)是一个功能强大的 DNS 查询工具,能够向 DNS 服务器发送查询请求并获取详细的响应信息。如果需要查询单个域名的 IP 地址,可以使用命令 dig 2daygeek.com +short 。此外,还可以通过编写 bash 脚本,将包含域名的文本文件中的域名逐个读取,然后利用 dig 命令进行查询,从而实现批量查询域名 IP 地址的功能。 其次,host 命令是一个简单易用的 DNS 查询工具,主要用于将域名解析为 IP 地址。要获取某个域名的 IP 地址,直接使用 host 2daygeek.com 即可。如果只想显示 IP 地址部分,可以通过管道结合 grep 和 sed 命令来实现,例如:host 2daygeek.com | grep "has address" | sed s/has address/-/g 。 再者,nslookup 命令也是一种常用的 DNS 查询工具,它支持交互式查询 DNS 信息。通过 nslookup 2daygeek.com 可以查询域名的 IP 地址。若要以非交互式的方式只显示 IP 地址,可以使用命令 nslookup 2daygeek.com | awk /^Address:/ {print $2} 。 另外,fping 命令与传统的 ping 命令不同,它不会直接进行 DNS 查询,而是通过发送 ICMP Echo Request(pi
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值