Java单例的写法详解

 更新时间:2021年09月10日 11:05:06   作者:茕祇  
在java中,单例有很多种写法,面试时,手写代码环节,除了写算法题,有时候也会让手写单例模式,这里记录一下单例的几种写法和优缺点。需要的朋友可以参考下

单例模式,顾名思义,就是全局只保存有一个实例并且能够避免用户去手动实例化,所以单例模式的各种写法都有一个共同点,不能通过new关键字去创建对象,因此,如果能够通过构造方法实例化,那么就一定要将其声明为私有。

饿汉式

public class PersonResource {
    public static final PersonResource PERSON_RESOURCE_SINGLETON = new PersonResource();
    private PersonResource(){}
    public  static PersonResource getInstance() {
        return PERSON_RESOURCE_SINGLETON;
    }
}

这种方式可以说是最安全,也最简单的了,但却有一个缺点,那就是无论这个实例有没有被使用到,都会被实例化,颇有些浪费资源

懒汉式一

既然前一种方法有些浪费资源,那就换一种写法,让类在被调用的时候实例化

public class PersonResource {
    private static PersonResource personResourceSingleton;
    private PersonResource() {
    }
    public static PersonResource getPersonResourceSingleton(){
        if(null==personResourceSingleton){
            personResourceSingleton = new PersonResource();
        }
        return personResourceSingleton;
    }
}

这种方式能够在需要用到该实例的时候再初始化,也能够在单线程下很好的运行,但如果是多线程就容易出现问题了。

懒汉式二

public class PersonResource {
    private static PersonResource personResourceSingleton;
    private PersonResource() {
    }
    public static PersonResource getPersonResourceSingleton(){
        if(null==personResourceSingleton){
            personResourceSingleton = new PersonResource();
        }
        return personResourceSingleton;
    }
}

多线程之所以会出现问题,是因为多个线程能够并发执行getPersonResourceSingleton方法,从而导致在判断是否为空时出现问题。

既然如此,加上锁 ,使其互斥即可。这里又出现了一个问题,每次获取实例的时候都需要加锁解锁,而当一个实例已经被产生后,再加锁就有些多余了;

懒汉式三(双重检查)

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

既然实例确定产生后不再需要加锁,那我们在获取锁前先判断一次是否已经有实例存在就可以解决问题了

静态内部类

public class PersonResource {
    private PersonResource(){}
    private static class PersonResourceHolder{
        public static PersonResource personResourceSingleton = new PersonResource();
    }
    public static PersonResource getInstance(){
        return PersonResourceHolder.personResourceSingleton;
    }
}

除了双重检查能够保证安全的单例外,用一个静态内部类去持有单例也是可以的,静态内部类保证了不会随外部类的加载而加载,这保证了延迟加载,同时在加载该类的时候就实例化单例,保证了线程安全;

枚举

public enum PersonResource {
    /**
     * PersonResource单例
     */
    personResource;
    public void setPersonResource(){
    }
}

以上几种方式基本就够用了,但都有一个共同的缺点,面对序列化和反序列化,是无法保证单例的,但枚举的特性却能保证这一点

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!

相关文章

  • Java8 String内存优化之字符串常量池详解

    Java8 String内存优化之字符串常量池详解

    这篇文章主要介绍了Java8 String内存优化之字符串常量池,具有很好的参考价值,希望对大家有所帮助,
    2023-07-07
  • java实现科学计算器的全过程与代码

    java实现科学计算器的全过程与代码

    最近编写了一个功能较全面的科学计算器,该计算器不仅能进行加、减、乘、除等混合运算,而且能计算sin、cos、tan、log等函数的值,还要具有清零、退格、求倒数、求相反数等功能,这篇文章主要给大家介绍了关于java实现科学计算器的相关资料,需要的朋友可以参考下
    2022-06-06
  • SpringBoot整合ActiveMQ的详细步骤

    SpringBoot整合ActiveMQ的详细步骤

    昨天仔细研究了activeMQ消息队列,也遇到了些坑,下面这篇文章主要给大家介绍了关于SpringBoot整合ActiveMQ的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-11-11
  • 浅谈Java父子类加载顺序

    浅谈Java父子类加载顺序

    本文主要介绍了Java父子类加载顺序,那么这么长怎么记呀?本文就帮大家总结一下,更有利于记忆,感兴趣的可以了解一下
    2021-08-08
  • Java编程实现获取mp3时长及播放mp3文件的方法

    Java编程实现获取mp3时长及播放mp3文件的方法

    这篇文章主要介绍了Java编程实现获取mp3时长及播放mp3文件的方法,涉及java基于jaudiotagger与jl包对MP3音频文件属性操作及音频播放相关操作技巧,并提供了相关jar包的本站下载,需要的朋友可以参考下
    2018-02-02
  • Java集合框架之Set和Map详解

    Java集合框架之Set和Map详解

    大家好,本篇文章主要讲的是Java集合框架之Set和Map详解,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览
    2021-12-12
  • spring整合JMS实现同步收发消息(基于ActiveMQ的实现)

    spring整合JMS实现同步收发消息(基于ActiveMQ的实现)

    本篇文章主要介绍了spring整合JMS实现同步收发消息(基于ActiveMQ的实现),具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-10-10
  • 关于MyBatis中SqlSessionFactory和SqlSession简解

    关于MyBatis中SqlSessionFactory和SqlSession简解

    这篇文章主要介绍了MyBatis中SqlSessionFactory和SqlSession简解,具有很好的参考价值,希望大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • 以Java代码为例讲解设计模式中的简单工厂模式

    以Java代码为例讲解设计模式中的简单工厂模式

    简单来说,工厂模式就是按照需求来返回一个类型的对象,使用工厂模式的意义就是,如果对象的实例化与代码依赖太大的话,不方便进行扩展和维护,使用工厂的目的就是使对象的实例化与主程序代码就行解耦.来具体看一下:
    2016-05-05
  • IDEA配置静态资源热加载操作(Springboot修改静态资源不重启)

    IDEA配置静态资源热加载操作(Springboot修改静态资源不重启)

    这篇文章主要介绍了IDEA配置静态资源热加载操作(Springboot修改静态资源不重启),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-10-10

最新评论