设计模式——单例模式

422 阅读2分钟

概念

  • 创建型模式
  • 通过单例模式的方法创建的类在当前进程中只有一个

场景

  • 数据库线程池
  • spring bean(单例)

单例细分

sequenceDiagram
问->>答: 最简单的?
答-->>问: 01、饿汉式———线程安全
问-)答: 类太多,服务启动太慢怎么办?
答-->>问: 02、懒汉式——线程不安全
问-)答: 这个线程不安全?
答-->>问: 03、懒汉式——线程安全(同步)
问-)答: 方法使用sychronized,影响性能?
答-->>问: 04、懒汉式——线程安全(双重锁校验)
问-)答: 使用JUC能实现吗?
答-->>问: 05、懒汉式——线程安全(CAS高并发)
问-)答: 无锁化能吗?
答-->>问: 06、懒汉式——线程安全(内部类)
问-)答: 枚举类能搞吗?
答-->>问: 07、枚举式——线程安全

01、饿汉式———线程安全

  • 程序启动,实例化对象
  • 类多会导致启动缓慢
  • 可能某些类,只需在使用时实例化
public class HungrySafe{
    //方式一:静态常量
    private static final HungrySafe hungrySafe=new HungrySafe();
    
    //方式二:
    private static final HungrySafe hungrySafe;
    static{
        hungrySafe=new HungrySafe();
    }
    public static HungrySafe getInstance(){
        return hungrySafe;
    }
}

//测试
public class HungrySafeTest {
    public static void main(String[] args) {
        HungrySafe map=HungrySafe.getInstance();
        HungrySafe map2=HungrySafe.getInstance();
        System.out.println(map);
        System.out.println(map2);
    }
}

02、懒汉式(线程不安全)

  • 构造函数私有化
  • 第一次使用时,创建实例
  • 多线程会产生多实例(不安全)
public class LazyUnSafe {
    private static LazyUnSafe lazyUnSafe;
    private LazyUnSafe(){ }

    public static LazyUnSafe getInstance(){
        if(lazyUnSafe!=null){
            return lazyUnSafe;
        }
        lazyUnSafe= new LazyUnSafe();
        return lazyUnSafe;
    }
}

//测试
class LazyUnSafeTest {
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(()->{
            LazyUnSafe lazyUnSafe=LazyUnSafe.getInstance();
            System.out.println(lazyUnSafe);
        });
        t.start();
        //t.join(); //此处测试线程安全性
        LazyUnSafe lazyUnSafe=LazyUnSafe.getInstance();
        System.out.println(lazyUnSafe);
    }
}

03、懒汉式-同步 (线程安全)

  • 方法增加synchoronized关键字(同步锁)
  • 所有的访问都需要 锁占用(获取/释放锁)
  • 不建议使用
public class LazySafeSync {
    private static LazySafeSync lazySafeSync=new LazySafeSync();
    private LazySafeSync(){}
    public static synchronized LazySafeSync getInstance(){
        if(lazySafeSync!=null){
            return lazySafeSync;
        }
        return lazySafeSync;
    }
}

//测试
class LazySafeSyncTest {
    public static void main(String[] args) {
        Thread t=new Thread(()->{
            LazySafeSync lazySafeSync=LazySafeSync.getInstance();
            System.out.println(lazySafeSync);
        });
        t.start();
        LazySafeSync lazySafeSync=LazySafeSync.getInstance();
        System.out.println(lazySafeSync);
    }
}

04、懒汉式-双重锁校验(线程安全)

  • synchoronized关键字不使用在方法上
  • 对类对象进行加锁
  • 性能有所提升(对比03)
public class LazySafeSyncX {
    private static volatile LazySafeSyncX lazyUnSafe;
    private LazySafeSyncX(){}
    public static LazySafeSyncX getInstance(){
        if(lazyUnSafe!=null){
            return lazyUnSafe;
        }
        synchronized (LazySafeSync.class){
            if(lazyUnSafe==null){
                lazyUnSafe=new LazySafeSyncX();
            }
        }
        return lazyUnSafe;
    }
}

//测试
class LazySafeSyncXTest {
    public static void main(String[] args) {
        Thread t=new Thread(()->{
            LazySafeSyncX lazySafeSyncX=LazySafeSyncX.getInstance();
            System.out.println(lazySafeSyncX);
        });
        t.start();
        LazySafeSyncX lazySafeSyncX=LazySafeSyncX.getInstance();
        System.out.println(lazySafeSyncX);
    }
}

05、懒汉式-CAS(线程安全)

  • CAS算法,AtomicReference原子类
  • 支持高并发,无线程切换和阻塞
  • 竞争激烈会导致一直循环等待-->死循环(CPU性能)
public class LazySafeAtomic {
    private static final AtomicReference<LazySafeAtomic> reference=new AtomicReference<>();
    private LazySafeAtomic(){ }

    public static LazySafeAtomic getInstance(){
        for (;;){
            LazySafeAtomic lazySafeAtomic=reference.get();
            if(lazySafeAtomic!=null){
                return lazySafeAtomic;
            }
            reference.compareAndSet(null,new LazySafeAtomic());
            return reference.get();
        }
    }
}

//测试
class LazySafeAtomicTest {
    public static void main(String[] args) {
        Thread t=new Thread(()->{
            LazySafeAtomic lazySafeAtomic=LazySafeAtomic.getInstance();
            System.out.println(lazySafeAtomic);
        });
        t.start();
        LazySafeAtomic lazySafeAtomic=LazySafeAtomic.getInstance();
        System.out.println(lazySafeAtomic);
    }
}

06、懒汉式-内部类(线程安全)

  • 静态内部类保证创建唯一实例
  • 懒加载,线程安全,无锁化性能高
  • 推荐使用
public class LazySafeInner {
    private LazySafeInner(){ }
    private static class LazySafeInnerHolder{
        private static LazySafeInner lazySafeInner=new LazySafeInner();
    }
    public static LazySafeInner getInstance(){
        return LazySafeInnerHolder.lazySafeInner;
    }
}

//测试
class LazySafeInnerTest {
    public static void main(String[] args) {
        Thread t=new Thread(()->{
            LazySafeInner lazyUnSafe=LazySafeInner.getInstance();
            System.out.println(lazyUnSafe);
        });
        t.start();
        LazySafeInner lazyUnSafe=LazySafeInner.getInstance();
        System.out.println(lazyUnSafe);
    }
}

07、枚举式(线程安全)

  • 推荐
  • 线程安全、自由串行化、单一实例
  • 防止反射
  • 不适用继承场景
public enum LazySafeEnum {
    INSTANCE;
    public void hello(){
        System.out.println("hello ");
    }
}

//测试
class LazySafeEnumTest {
    public static void main(String[] args) {
        LazySafeEnum.INSTANCE.hello();
    }
}