单例模式

一个单一的类,负责创建自己的对象,同时确保系统中只有单个对象被创建。

单例特点

•某个类只能有一个实例;(构造器私有)

•它必须自行创建这个实例;(自己编写实例化逻辑)

•它必须自行向整个系统提供这个实例;(对外提供实例化方法)

单例模式之懒汉式

顾名思义,饿汉式就是在需要使用实例的时候才创建实例

先创建一个普通的Person类,用于实现懒汉式

package com.nkym;
public class Person {
    private String name;
    private String age;

    //保证一个类只有一个用于返回的对象
    private static Person instance;
    //私有化构造器,保证外部无法创建实例。
    private Person(){
        System.out.println("对象创建了");
    }
    //创建实例
    public static Person getInstance(){
        //如果instance为空则新 new 一个对象
        if(instance==null){
            instance = new Person();
        }
        //如果不为空,则直接返回
        return instance;
    }
}

测试

JAVA懒汉模式和饿汉模式多例 懒汉式和饿汉式类图_开发语言

我们发现只有运行了一次构造器方法。并且获取的三个实例的引用都是相同的。指向的同一对象。

这样单例模式之懒汉式就设计好了。但是光这样是线程不安全的。当有并发出现时,会new出多个实列。

所以我们要给饿汉式加锁,让它变成线程安全的。

1、给getInstance方法枷锁(效率不高,适用于多线程环境)

这样每次调用getInstance都会上锁,效率不高

//给方法加锁。
public static synchronized Person getInstance(){
    //如果instance为空则新 new 一个对象
    if(instance==null){
        instance = new Person();
    }
    //如果不为空,则直接返回
    return instance;
}

2、方法内加锁(效率不高,适用于多线程环境)

同样每次调用getInstance都会上锁,效率不高

public static Person getInstance() {
    //加synchronized锁
    synchronized (Person.class) {
        //如果instance为空则新 new 一个对象
        if (instance == null) {
            instance = new Person();
        }
    }
    //如果不为空,则直接返回
    return instance;
}

3、双重检验锁(适用于多线程,效率相对更高,推荐使用)

package com.nkym;/*
 * @ClassName Person
 * @Desc TODO
 * @Author 19637
 * @Date 2022/2/19 19:15
 * @Version 1.0
 */

public class Person {
    private String name;
    private String age;
//------------------------有变化的地方-------------------------------------------
    //volatile修饰成员变量 阻止指令重排序
    private static volatile Person instance;

    
    
    
    //私有化构造器,保证外部无法创建实例。
    private Person() {
        System.out.println("对象创建了");
    }
    
    
    
    
//------------------------有变化的地方-------------------------------------------
    //获取实例实例
    public static Person getInstance() {
        if (instance == null) {
            //实例为空再加锁
            synchronized (Person.class) {
                if (instance == null) {
                    instance = new Person();
                }
            }
        }
        //如果不为空,则直接返回
        return instance;
    }
}

单例模式之饿汉式。

饿汉式就是在类加载的时候就创建实例。饿汉式本身就是线程安全的

package com.nkym;/*
 * @ClassName Person
 * @Desc TODO
 * @Author 19637
 * @Date 2022/2/19 19:15
 * @Version 1.0
 */

public class Person {
    private String name;
    private String age;

    //类加载就创建实例,加上final关键字,防止重复创建
    private static final Person instance = new Person();

    //私有化构造器,保证外部无法创建实例。
    private Person() {
        System.out.println("对象创建了");
    }
	//获取实例的方法
    public static Person getInstance() {
        return instance;
    }
}

测试

JAVA懒汉模式和饿汉模式多例 懒汉式和饿汉式类图_JAVA懒汉模式和饿汉模式多例_02

我们发现只有运行了一次构造器方法。并且获取的三个实例的引用都是相同的。指向的同一对象。

这样单例模式之饿汉式就设计好了。并且不存在线程安全问题。