[Java] 单例模式的学习笔记(Java版)

  1. 饿汉模式

立即加载的一种模式,使用 static 的属性,在类第一次运行的时候实例化这个类的实例。

public class MyObject {
    private static MyObject myObject = new MyObject();

    private MyObject() {
    }

    // 缺点: 不能有其他实例变量
    // 因为 getInstance 没有加锁,所以可能会出现多线程同步问题
    public static MyObject getInstance() {
        return myObject;
    }
}
  1. 懒汉模式
public class MyObject {
    private static MyObject myObject;

    private MyObject() {
    }

    // 使用的时候才加载
    // 但是这个方法同样没有加锁,所以多线程一样会出现非单例情况
    public static MyObject getInstance() {
        if (null == myObject)
            myObject = new MyObject();

        return myObject;
    }
}

针对懒汉模式出现多个实例的解决方案:

2.1 使用锁 synchronized

public class MyObject {
    private static MyObject myObject;

    private MyObject() {
    }

    public synchronized static MyObject getInstance() {
        if (null == myObject)
            myObject = new MyObject();

        return myObject;
    }
}

这种方式虽然可以解决多线程多对象的烦恼,但是却是比较影响程序运行速度的,于是,进一步优化。

2.2 使用 synchronized 同步代码块

public class MyObject {
    private static MyObject myObject;

    private MyObject() {
    }

    public static MyObject getInstance() {
        synchronized (MyObject.this) {
            if (null == myObject)
                myObject = new MyObject();

            return myObject;
        }
    }
}

这种和2.1 的基本类似,效率也是比较低的,于是进一步做优化。

2.3 使用 synchronized 同步部分代码块
// 宗旨就是,相互独立的可以分别进行实例化,共享资源一定需要加锁使其变成单例。

public class MyObject {
    private static MyObject myObject;

    private MyObject() {
    }

    public static MyObject getInstance() {

        if (null == myObject) {
            // do somethings
            synchronized (MyObject.this) {
                myObject = new MyObject();
            }
        }

        return myObject;
    }
}

但是这种却不是线程安全的,在多线程下,依然会有可能产生多个实例。

2.4 使用 DCL 双检查锁机制

public class MyObject {
    private volatile static MyObject myObject;

    private MyObject() {
    }

    public static MyObject getInstance() {

        if (null == myObject) {
            // do somethings
            synchronized (MyObject.this) {
                if (null == myObject) {
                    myObject = new MyObject();
                }
            }
        }

        return myObject;
    }
}
  1. 使用静态内部类实现单例模式
public class MyObject {

    // 内置类方式
    private static class MyObjectHandler {
        private static MyObject myObject = new MyObject();
    }

    private MyObject() {

    }

    public static MyObject getInstance () {
        return MyObjectHandler.myObject;
    }
}

// 摘录: 静态内部类是可以达到线程安全问题,但如果遇到序列化对象时,使用默认的方式运行得到的结果还是多例的。
// 如果碰到了序列化 IO 流对象,都是多例的,这是正常的。
4. 序列化与反序列化的单例模式的实现

public class MyObject implements Serializable {

    private static final long serialVersionUID = 888L;

    // 内置类方式
    private static class MyObjectHandler {
        private static MyObject myObject = new MyObject();
    }

    private MyObject() {

    }

    public static MyObject getInstance () {
        return MyObjectHandler.myObject;
    }

    // TODO: 关于这个方法网上是怎么说的
    protected Object readResolve() throws ObjectStreamException {
        System.out.println("go into readResolve");
        return MyObjectHandler.myObject;
    }
}


public class staticNestSingleton {
    public static void main(String[] args) {
        try {
            MyObject myObject = MyObject.getInstance();
            FileOutputStream fosRef = new FileOutputStream(new File("myObjectFile.txt"));

            ObjectOutputStream oosRef = new ObjectOutputStream(fosRef);
            oosRef.writeObject(myObject);
            oosRef.close();
            fosRef.close();
            System.out.println(myObject.hashCode());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            FileInputStream fisRef = new FileInputStream(new File("myObjectFile.txt"));
            ObjectInputStream iosRef = new ObjectInputStream(fisRef);
            MyObject newObject = (MyObject) iosRef.readObject();
            iosRef.close();
            fisRef.close();
            System.out.println(newObject.hashCode());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
  1. 使用 static 代码块实现单例
public class MyObject {

    private static MyObject myObject = null;

    private MyObject() {
    }

    static {
        myObject = new MyObject();
    }

    public static MyObject getInstance () {
        return myObject;
    }
}
  1. 使用 enum 枚举数据类型实现单例模式
  2. 完善使用 enum 枚举实现单例模式

猜你喜欢

转载自blog.csdn.net/haonanren2bu2/article/details/49925909