谈谈java的单例模式吧

单例模式,顾名思义就是单个实例,就是说一个类有且仅有一个实例,应该是23中设计模式中最简单也最好理解的设计模式了,同时简单的往往也是重要的和常用的,对吧?简单的往往也是常用的,这句话在任何地方都能适用

 

一、常见的几种写法

1、饿汉式(可以使用)

特点:线程安全的,不能实现延迟加载

public class HungryMan {


    /**1、私有化构造器:所有的单例模式第一步永远都是私有化构造器,因为只有不让在外面调用构造器new 
     *  对象了,才能控制对象的数量,这是单例模式的前提
     */
    private HungryMan(){}

    //2、内的内部创建出实例
    private static final HungryMan HUNGRY_MAN = new HungryMan();

    //3、提供公共静态的方法返回实例
    public static HungryMan getInstance(){
        return HUNGRY_MAN;
    }
}

1.1饿汉式之静态代码块版(可以使用)

特点:线程安全的,不能实现延迟加载

public class HungryMan1 {

    private HungryMan1(){}

    private static HungryMan1 hungryMan1;

    static {
        hungryMan1 = new HungryMan1();
    }

    public static HungryMan1 getInstance(){
        return hungryMan1;
    }
    
}

2、懒汉式(不推荐使用)

特点:不是线程安全的,能延迟加载

public class LazyMan {

    private LazyMan(){}

    private static LazyMan lazyMan;

    public static LazyMan getInstance() {
        if (lazyMan == null) {
            lazyMan = new LazyMan();
        }
        return lazyMan;
    }
}

2.1懒汉式之同步方法版(可以使用)

特点:线程安全的,能延迟加载,但效率低(当有多个线程同时调用时,不管有没有实例都要等待拿锁)

public class LazyMan1 {

    private LazyMan1(){}

    private static LazyMan1 lazyMan1;

    public static synchronized LazyMan1 getInstance(){
        if (lazyMan1 == null) {
            lazyMan1 = new LazyMan1();
        }
        return lazyMan1;
    }
}

2.2懒汉式之同步代码块版(可以使用)

特点:线程安全的,能延迟加载,但效率低

public class LazyMan2 {

    private LazyMan2(){}

    private static LazyMan2 lazyMan2;

    public static LazyMan2 getInstance(){
        synchronized (LazyMan2.class){
            if (lazyMan2 == null) {
                lazyMan2 = new LazyMan2();
            }
            return lazyMan2;
        }
    }
}

2.3懒汉式之双重检查版(较推荐使用)

特点:线程安全的,能延迟加载,效率高(据说双重检查有线程安全问题,不确定还)

public class LazyMan3 {

    private LazyMan3(){}

    private static LazyMan3 lazyMan3;

    public static LazyMan3 getInstance(){
        if (lazyMan3 == null){
           synchronized (LazyMan3.class){
              if (lazyMan3 == null) {
                 lazyMan3 = new LazyMan3();
               }
           }
        }
        return lazyMan3;
    }
}

3、静态内部类版(推荐使用)

特点:线程安全,能延迟加载,效率高

public class StaticInsideClass {

    private StaticInsideClass(){}

    //在静态内部类中创建外部类的实例
    //PS:静态内部类会等到它被调用的时候才加载
    private static class InnerClass{
        private static final StaticInsideClass STATIC_INSIDE_CLASS = new StaticInsideClass();
    }

    public static StaticInsideClass getInstance(){
        return InnerClass.STATIC_INSIDE_CLASS;
    }
}

4、枚举类版(推荐使用)

特点:线程安全的,效率高,能避免反射和反序列化创建对象的问题,不能延迟加载

public enum EnumSingleton {

      //被枚举出来的对象
      Instance;



    /*当前枚举类的其他属性和方法*/
      //名字
      private String name;
      //年龄
      private Integer age;


    public void doSomeThing(){
        System.out.println("当前枚举出来的对象做一些事情~~~");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

5、登记式:用一个线程安全的Map来保存对象实例。在此就不写了,大家可以自己实现一下。

二、常见的应用场景

首先,想一下单例模式的特点:在一个系统中只有一个对象实例,我们可以好好设计这个类,比如设计一些读取和写入的方法,来对类中的属性(比如集合等)进行操作,因为就只有一个对象,该对象拥有自己的一套属性和方法,即有自己的内存空间,这样该类就能成为系统运行期间的一个小的内存数据库。(当前要保存该类不会被JVM当成垃圾回收了才行)

1、系统配置文件的读取时,对应一个单例的类。

2、网站计数器来记录网站访问的次数、在线人数等

3、临时对象的频繁创建和销毁时,比如需要创建一个对象来保存数据,然后进行插入数据库操作时。

4、各种池的创建都是单例模式的,比如数据库连接池、线程池等。

总之一句话,凡是需要保证一份资源只能有一份时,就用单例模式。

三、问题

这里我有个问题先记下来:为什么单例模式的对象不会被JVM当成垃圾回收?

答:  等我了解完JVM的知识后再来填坑吧

聪明的小伙伴看到后,能否在我填坑前,在评论区留言解答呢?说出你的看法,show time~~

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值