学习资源来自于哔哩哔哩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.(虽然我单个锁检测了好久都没出问题