单例

懒汉式(非线程安全)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
 * 懒汉式单例
 * 特点:用时加载
 */
public class Singleton implements Serializable {
    
    /**
     * 核心为静态变量
     */
    private static Singleton instance;

    /**
     * 私有构造方法
     */
    private Singleton() {
    }

    /**
     * 工厂方法
     * @return
     */
    private static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

比较容易忽略的就是构造方法私有

懒汉式(线程安全)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
 * 线程安全懒汉式单例
 * 特点:用时加载,线程安全
 */
public class Singleton implements Serializable {
    
    /**
     * 核心为静态变量
     * 加volatile确保异步可见性
     */
    private static volatile Singleton instance;

    /**
     * 私有构造方法
     */
    private Singleton() {
    }

    /**
     * 工厂方法
     * 加锁确保线程安全
     * @return
     */
    private static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

这种方式把synchornized加在工厂方法上,导致每次调用工厂方法都会阻塞,从而效率低下。

双重锁(DLC),线程安全

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
/**
 * 双重锁单例
 * 线程安全
 */
public class DlcSingleton {
    private static volatile DlcSingleton instance;

    private DlcSingleton() {
    }

    public static DlcSingleton getInstance() {
        if (instance == null) {// 避免阻塞,提高效率
            synchronized (DlcSingleton.class) {
                if (instance == null) {//防止二次创建
                    instance = new DlcSingleton();
                }
            }
        }
        return instance;
    }
}

双重锁的特点就是在工厂方法中加入了同步代码块和双重if判断,使得线程安全。容易忘掉的是静态变量添加的volatile关键字。

考点:

静态内部类懒汉式(线程安全)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
/**
 * 静态内部类懒汉式
 */
public class InnerSingleton {
    /**
     * 私有构造方法
     */
    private InnerSingleton(){}

    /**
     * 静态内部类
     */
    private static class InnerSingletonHolder{
        private static final InnerSingleton INSTANCE = new InnerSingleton();
    }

    public static final InnerSingleton getInstance(){
        return InnerSingletonHolder.INSTANCE;
    }
}

主要是靠静态内部类持有静态实例。

初看上去写法很饿汉式很像,但是在使用时,加载InnerSingleton类型时,并不会同时加载其静态内部类,只有调用工厂方法时,才会加载其静态内部类,并同时初始化instance,所以这个也算是懒汉式。

classLoader加载内部静态类时,会直接初始化instance,所以也保证了线程安全。

静态内部类,不持有外部类的引用,它其实完全就是另一个独立的类。

饿汉式(线程安全)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
 * 饿汉式单例
 * 特点:用前加载,天生线程安全,不如懒汉式灵活
 */
public class Singleton implements Serializable {

    /**
     * 核心为静态变量
     * 加volatile确保异步可见性
     */
    private static final Singleton instance = new Singleton();

    /**
     * 私有构造方法
     */
    private Singleton() {
    }

    /**
     * 工厂方法
     * 
     * @return
     */
    private static Singleton getInstance() {
        return instance;
    }
}

枚举饿汉式(线程安全)

1
2
3
4
public enum SingletonEnum {
    INSTANCE;
    
}

在java中,枚举就是一种特别的类,它具备class的一切特性,并且由于跟饿汉差不多,所以天然的线程安全。