首页 > 技术文章 > 单例模式笔记

tanshishi 2020-05-31 21:39 原文

image-20200531213054908

学习资源来自于哔哩哔哩UP遇见狂神说,一个宝藏UP大家快去关注吧!记得三连加分享,不要做白嫖党.

单例模式

饿汉式单例

public class Hungry {
    private Hungry() {

    }

    private static final Hungry HUNGRY= new Hungry();

    public static Hungry getInstance() {
        return HUNGRY;
    }

}

**单例模式中最重要的思想: **构造器私有,一旦构造器私有被人就没有办法new这个对象,保证内存中只有一个对象.

饿汉式一上来就new出来这个对象,这样就可以保证它是唯一的.再抛出一个对外的方法.

饿汉式的问题: 一上来就会把所有东西加载出来,非常耗内存资源,可能会浪费空间

解决方法: 想要用的时候再去创造这个对象,平时就放着,于是就出来了懒汉式单例

懒汉式单例

//懒汉式单例
public class LazyMan {

    private LazyMan() {
        System.out.println(Thread.currentThread().getName() + "ok");
    }

    private static LazyMan lazyMan;

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

当对象为空时才创建对象.

问题: 单线程下确实OK,但是多线程并发下有问题

写一个多线程的main方法:

public static void main(String[] args) {
    for (int i = 0; i < 10; i++) {
        new Thread(() -> {
            lazyMan.getInstance();
        }).start();
    }
}

输出:
Thread-8ok
Thread-7ok
Thread-5ok
Thread-2ok
Thread-3ok
Thread-1ok
Thread-4ok
Thread-9ok
Thread-0ok(每次结果都不一样)

多线程下有问题无法单例,

那么我们就得加一把锁,但我们得考虑一种情况:
两个线程同时到达,即同时调用 getInstance() 方法,此时由于 lazyMan == null ,所以很明显,两个线程都可以通过第一重的 lazyMan == null ,进入第一重 if语句后,由于存在锁机制,所以会有一个线程进入 lock 语句并进入第二重 lazyMan == null ,而另外的一个线程则会在 lock 语句的外面等待.

所以需要双重锁检测null.(虽然我单个锁检测了好久都没出问题

推荐阅读