Java单例模式

Java中的单例模式有5种实现方式

  1. 饿汉式

    1
    2
    3
    4
    5
    6
    7
    8
    public class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton(){}

    public static Singleton getInstance(){
    return instance;
    }
    }
  2. 懒汉式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class Singleton2 {
    private static Singleton2 instance ;
    private Singleton2(){}

    public static synchronized Singleton2 getInstance(){
    if(instance == null){
    instance= new Singleton2();
    }
    return instance;
    }
    }
  3. 双重检查机制

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class Singleton3 {
    private static Singleton3 instance;
    private Singleton3(){}

    public static Singleton3 getInstance(){
    if(instance ==null){
    Singleton3 inst;
    synchronized (Singleton3.class){
    inst = instance;
    if(inst == null){
    synchronized (Singleton3.class){
    inst = new Singleton3();
    }
    }
    instance = inst;
    }
    }
    return instance;
    }
    }
  4. 静态类实现方式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class Singleton4 {
    private static class SingletonClassInstance{
    private static final Singleton4 instance = new Singleton4();
    }
    private Singleton4(){}

    public static Singleton4 getInstance(){
    return SingletonClassInstance.instance;
    }
    }
  5. 枚举类实现方式

    1
    2
    3
    4
    5
    6
    public enum Singleton5 {
    INSTANCE;

    public void singletonOperaton(){
    }
    }
  6. 如何选择:

    • 单例对象如果占用资源少,不需要延时加载: 枚举 之后 饿汉
    • 单例对象如果占用资源多,需要延时加载: 静态内部类
    • 懒汉式因为有同步代码块所以效率比较低
    • 双重检查机制,JVM内部模型和编译器优化原因,偶尔出现问题.不建议使用.
  7. 单例模式的破解与防止.
    • 反射获取对象实例: 通过在私有构造器中添加判断避免,可以参看Singleton2
    • 正反序列化获取对象实例:通过添加 readResolve() 可以避免
  8. 测试.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class App {
    public static void main(String[] args) throws InterruptedException {
    int threadNum=1000;
    final CountDownLatch latch = new CountDownLatch(threadNum);
    long start = System.currentTimeMillis();
    for (int i = 0; i < threadNum; i++) {
    new Thread(new Runnable() {
    @Override
    public void run() {
    for (int j = 0; j < 10000; j++) {
    Object obj = Singleton31.getInstance();
    }
    latch.countDown();
    }
    }).start();
    }
    latch.await();
    long end = System.currentTimeMillis();
    System.out.println("ms :"+(end -start));
    }
    }