学好Java设计模式--单例模式

单例模式的七种写法及简单分析

单例模式是最简单的设计模式之一,属于创建型模式,它提供了一种创建对象的方式,确保只有单个对象被创建。这个设计模式主要目的是想在整个系统中只能出现类的一个实例,即一个类只有一个对象。单例模式主要是为了解决创建对象时较耗资源耗时间的问题。

1、饿汉式写法

这种写法主要的问题是静态变量在类加载进内存时就会初始化,即使没有使用,并且不能防止用户通过反序列化的方式实例化对象。

package com.rul.designpattern.singleton;

/**
 * 饿汉式
 * 优点:写法简单
 * 缺点:即使不使用也会实例化一个对象,不能防止反序列化
 *
 * @author LuoRu
 */
public class Manager01 {
    private static Manager01 INSTANCE = new Manager01();

    //构造方法私有化
    private Manager01() {
    }

    public static Manager01 getInstance() {
        return INSTANCE;
    }

    //成员方法
    public void method() {

    }
}

2、饿汉式静态初始化块写法

本质与上一种写法一样,只是实例化时放入静态初始化块中。

package com.rul.designpattern.singleton;

/**
 * 饿汉式静态初始化块写法
 * 优点:写法简单,与Manager01写法本质一样
 * 缺点:即使不使用也会实例化一个对象,不能防止反序列化
 *
 * @author LuoRu
 */
public class Manager02 {
    private static Manager02 INSTANCE;

    static {
        INSTANCE = new Manager02();
    }

    //构造方法私有化
    private Manager02() {
    }

    public static Manager02 getInstance() {
        return INSTANCE;
    }

    //成员方法
    public void method() {

    }
}

3、懒汉式写法

这种写法只有在使用了的情况下才实例化对象,但是这种写法可能会导致在多线程环境下多个线程得到的实例不是同一个的问题,因为getInstance方法可能会被其他线程打断,同时也不能防止反序列化。

package com.rul.designpattern.singleton;

/**
 * 懒汉式
 * 优点:写法简单,只有使用到才会实例化一个对象
 * 缺点:多线程环境下不能保证单例,不能防止反序列化
 *
 * @author LuoRu
 */
public class Manager03 {
    private static Manager03 INSTANCE;

    //构造方法私有化
    private Manager03() {
    }

    public static Manager03 getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new Manager03();
        }
        return INSTANCE;
    }

    //成员方法
    public void method() {

    }
}

4、懒汉式加锁写法

这种写法解决了上一种写法在多线程环境中存在的问题,但是加锁导致了更多的性能开销,同样不能防止反序列化。

package com.rul.designpattern.singleton;

/**
 * 懒汉式加锁
 * 优点:写法简单,只有使用到才会实例化一个对象,多线程环境下能保证单例
 * 缺点:加锁影响效率,不能防止反序列化
 *
 * @author LuoRu
 */
public class Manager04 {
    private static Manager04 INSTANCE;

    //构造方法私有化
    private Manager04() {
    }

    //加锁,防止多线程环境下不止实例化一个对象问题
    public static synchronized Manager04 getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new Manager04();
        }
        return INSTANCE;
    }

    //成员方法
    public void method() {

    }
}

5、懒汉式双重判断加锁写法

这种写法解决了上一种写法性能过多开销问题,但写法稍复杂,并且同样不能防止反序列化。

package com.rul.designpattern.singleton;

/**
 * 懒汉式双重判断加锁
 * 优点:只有使用到才会实例化一个对象,多线程环境下能保证单例
 * 缺点:写法稍复杂,不能防止反序列化
 *
 * @author LuoRu
 */
public class Manager05 {
    //volatile防止指令重排序
    private static volatile Manager05 INSTANCE;

    //构造方法私有化
    private Manager05() {
    }

    //双重判断加锁
    public static Manager05 getInstance() {
        //外层判断保证只有未实例化时才加锁
        if (INSTANCE == null) {
            synchronized (Manager05.class) {
                //内层判断防止多线程环境下不止实例化一个对象
                if (INSTANCE == null) {
                    INSTANCE = new Manager05();
                }
            }
        }
        return INSTANCE;
    }

    //成员方法
    public void method() {

    }
}

6、懒汉式静态内部类写法

这种写法较为理想,因为外部类在加载时并不会加载静态内部类,所以实现了懒加载,但同样不能防止反序列化。

package com.rul.designpattern.singleton;

/**
 * 懒汉式静态内部类
 * 优点:写法简单,只有使用到才会实例化一个对象,多线程环境下能保证单例
 * 缺点:不能防止反序列化
 *
 * @author LuoRu
 */
public class Manager06 {

    //使用静态内部类保证只有使用到才实例化一个对象
    private static class ManagerHolder {
        private static Manager06 INSTANCE = new Manager06();
    }

    //构造方法私有化
    private Manager06() {
    }

    public static Manager06 getInstance() {
        return ManagerHolder.INSTANCE;
    }

    //成员方法
    public void method() {

    }
}

7、枚举单例写法

《Effective Java》作者(同时也是Java开发人员之一)提供的一种写法,通过枚举类解决了反序列化问题,因为枚举类是不提供构造方法的,所以用户并不能通过反射机制反序列化实例。但枚举类的写法给人的感觉不是很友好,不容易理解。

package com.rul.designpattern.singleton;

/**
 * 枚举单例
 * 优点:多线程下能保证单例,能防止反序列化
 * 缺点:不容易理解
 *
 * @author LuoRu
 */
public enum Manager07 {
    //使用Manager07.INSTANCE.method()调用成员方法
    INSTANCE;

    //成员方法
    public void method() {

    }
}

你可能感兴趣的:(设计模式)