【无标题】

  1.单例模式简介

单例模式:所谓单例模式就是确保某一个类在全局只有一个实例,并且提供一个全局访问的唯一入口(全局任何地方访问该实例,必须通过该入口访问)。

单例模式三个特点:

  • 一、它在全局只有一个实例。

  • 二、该实例创建是在该类内部处理。

  • 三、对外提供全局访问的唯一入口:点。

2.解决了什么问题

有时候某些对象我们只需要一个,如:线程池、缓存、对话框等等,对于这类对象我们只能有一个实例,如果我们制造出多个实例,就会导致很多问题产生。这种场景需要做到两点:

1.全局能访问 2.只有一个实例

备注:全局变量只能满足全局访问,但不能解决只有一个实例的困扰。单例模式能全部解决。

单例模式的优点:

1、节约了系统资源。由于系统中只存在一个实例对象,对与一些需要频繁创建和销毁对象的系统而言,单例模式无疑节约了系统资源和提高了系统的性能。

2、因为单例类封装了它的唯一实例的创建和它的访问方式,所以它可以严格控制客户怎样以及何时访问它该实例

单例模式的缺点:

1,由于单例模式中没有抽象层,因此单例模式不像策略模式一样易于扩展。

2、单例模式可能会因为多线程的问题而带来安全隐患。

3.策略模式结构图

【无标题】_第1张图片

4.特点

全局唯一实例,便于统一管理,也节省了资源

5.单例模式实战

单例模式的常见风险点是:在并发的情况下出现多个实例的创建

5.1 并发情况,线程不安全的单例模式

package main.java.org.example;

/**
 * lazy loading
 * 也称懒汉式
 * 虽然达到了按需初始化的目的,但却带来线程不安全的问题
 */
public class Mgr03 {
    private static Mgr03 INSTANCE;

    private Mgr03() {
    }

    public static Mgr03 getInstance() {
        if (INSTANCE == null) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            INSTANCE = new Mgr03();
        }
        return INSTANCE;
    }

    public void m() {
        System.out.println("m");
    }

    public static void main(String[] args) {
        for(int i=0; i<1000; i++) {
            new Thread(()->
                System.out.println(Mgr03.getInstance().hashCode())
            ).start();
        }
    }
}

 结果:

【无标题】_第2张图片

5.2 安全的单例模式写法

 方法1:


package main.java.org.example;

/**
 * 静态内部类方式
 * JVM保证单例
 * 加载外部类时不会加载内部类,这样可以实现懒加载
 */
public class Mgr07 {

    private Mgr07() {
    }

    private static class Mgr07Holder {
        private final static Mgr07 INSTANCE = new Mgr07();
    }

    public static Mgr07 getInstance() {
        return Mgr07Holder.INSTANCE;
    }

    public void m() {
        System.out.println("m");
    }

    public static void main(String[] args) {
        for(int i=0; i<100; i++) {
            new Thread(()->{
                System.out.println(Mgr07.getInstance().hashCode());
            }).start();
        }
    }


}

 方法2:最安全的方式

package main.java.org.example;

/**
 * 不仅可以解决线程同步,还可以防止反序列化。
 */
public enum Mgr08 {

    INSTANCE;
    
    public static void main(String[] args) {
        for(int i=0; i<100; i++) {
            new Thread(()->{
                System.out.println(Mgr08.INSTANCE.hashCode());
            }).start();
        }
    }

}

你可能感兴趣的:(java,开发语言)