0%

设计模式之单例模式(一)

单例模式简介

单例设计模式,就是采取一定的方法保证整个的软件系统中,对某个类只能存在一个对象实例,并且类只提供一个取得对象实例的方法(静态方法)。

单例模式有八种方式:

  1. 饿汉式(静态常量)
  2. 饿汉式(静态代码块)
  3. 懒汉式(线程不安全)
  4. 懒汉式(线程安全,同步方法)
  5. 懒汉式(线程安全,同步代码块)
  6. 双重检查
  7. 静态内部类
  8. 枚举

饿汉式(静态常量)

步骤如下:

  • 构造器私有化(防止通过 new 来创建对象——申请内存空间)
  • 类的内部创建对象
  • 向外暴露一个静态的公有方法(getInstance)

代码实现:

1
package com.yubulang.type01;
2
3
/**
4
 * 饿汉式(静态常量)
5
 */
6
public class Singleton {
7
    // 1. 私有化构造器,防止外部new创建对象
8
    private Singleton() {
9
    }
10
11
    // 2. 本类内部创建对象实例
12
    private final static Singleton instance = new Singleton();
13
14
    // 提供给一个公有的静态方法,返回实例对象
15
    public static Singleton getInstance() {
16
        return instance;
17
    }
18
}

测试代码:

1
package com.yubulang.type01;
2
3
import org.junit.Test;
4
5
public class SingletonTest {
6
    @Test
7
    public void test() {
8
        Singleton singleton01 = Singleton.getInstance();
9
        Singleton singleton02 = Singleton.getInstance();
10
        System.out.println(singleton01 == singleton02);
11
    }
12
}

优缺点说明:

优点:这个写法简单,就是在类装载的时候完成实例化。避免了线程同步问题。

缺点:在类装载的时候就完成实例化,没有达到 Lazy Loading 的效果。如果从始至终从未使用过这个实例,会造成内存浪费。

这种方式基于 classloader 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化,在单例模式中大多数都是调用 getInstance 方法,但是导致类装载的原因很多种,因此不能确定其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 就没有达到 lazyloading 的效果。

结论:这个单例模式可用,可能造成内存浪费

饿汉式(静态代码块)

1
package com.yubulang.type02;
2
3
/**
4
 * 饿汉式(静态常量)
5
 */
6
public class Singleton {
7
    // 私有化构造器,防止外部new创建对象
8
    private Singleton() {
9
    }
10
11
    // 本类内部声明
12
    private static Singleton instance;
13
14
    static {
15
        // 在静态代码块中创建单例对象
16
        instance = new Singleton();
17
    }
18
19
    // 提供给一个公有的静态方法,返回实例对象
20
    public static Singleton getInstance() {
21
        return instance;
22
    }
23
}

优缺点说明:

  • 这种方式和上面的方式其实类似,只不过将实例化的过程放在了静态代码块中,也是在类装载的时候,就执行静态代码块中的代码,初始化类的实例。优缺点和上面一样。
  • 结论:这种单例模式可用,但是可能造成内存浪费。

总结

贪多嚼不烂,我们就先记住两种饿汉式写法。其主要的中心思想还是将类构造私有化,提供一个静态方法创建实例对象,利用类加载器加载时创建来达到可用的安全单例,但是容易造成内存浪费。