设计模式-单例模式

Java中单例模式定义:“一个类有且仅有一个实例,并且自行实例化向整个系统提供。”

1.饿汉式

package testSingletonUnderMultiThreads;

/**
 * @author zhangdi
 * 饿汉式 : 存在效率和资源占用问题
 */
public class Singleton_1_MyObject {
// 饿汉式
private static Singleton_1_MyObject myObject = new Singleton_1_MyObject();

// private 只有内部才能调用构造器
private Singleton_1_MyObject() {
    super();
}

//
private static Singleton_1_MyObject getInstance() {
    return myObject;
}

}

2.懒汉式:存在多线程下的线程安全问题

package testSingletonUnderMultiThreads;

/**
 * @author zhangdi
 * 懒汉式:存在多线程下的线程安全问题
 */
public class Singleton_2_MyObject {
    // 定义一个静态变量来记录类的唯一实例,但不初始化
    private static Singleton_2_MyObject myObject;

    // 保证只有内部可以调用构造器
    private Singleton_2_MyObject() {

    }

    public static Singleton_2_MyObject getInstance() {
        if (null != myObject) {

        } else {
            myObject = new Singleton_2_MyObject();
        }
        return myObject;

    }
}

3.懒汉式加锁 :可解决多线程下的同步问题,但是存在严重效率问题


/**
 * @author zhangdi
 *  synchronized 加锁 : 可解决多线程下的同步问题,但是存在严重效率问题
 */
public class Singleton_3_MyObject {
    // 定义一个静态变量来记录类的唯一实例,但不初始化
    private static Singleton_3_MyObject myObject;

    // 保证只有内部可以调用构造器
    private Singleton_3_MyObject() {

    }

    //synchronized保证多线程下的懒汉式是线程安全的,但是问题在于,只有第一次执行时才需要同步,设置好MyObject后都不要同步这个方法了.
    synchronized public static Singleton_3_MyObject getInstance() {
        if (null != myObject) {

        } else {
            myObject = new Singleton_3_MyObject();
        }
        return myObject;

    }
}

4.DCL :双重加锁检查 :
volatile是必须的.

package testSingletonUnderMultiThreads;

/**
 * @author zhangdi
 * 双重加锁检查 
 */
public class Singleton_4_MyObject {
    //ps:volatile 保证线程间共享变量的可见性,但不能保证原子性
    //volatile确保myObject被初始化为singleton单例后,多个线程可以正确处理myObject
    private volatile static Singleton_4_MyObject myObject;

    private Singleton_4_MyObject() {
    }

    private static Singleton_4_MyObject getInstance() {
        //只有第一次才会彻底执行下面的代码
        if (myObject == null) {
            synchronized (Singleton_4_MyObject.class) {
                //进入区块后,再检查一下,myObject仍为null,才创建实例
                if(myObject == null){
                    myObject = new Singleton_4_MyObject();
                }
            }
        }
        return myObject;

    }
}

5 . 使用静态内部类 :静态内部类虽然保证了单例在多线程并发下的线程安全性,但是在遇到序列化对象时,默认的方式运行得到的结果就是多例的。
ps:静态内部类的加载不需要依附外部类,在使用时才加载,而不是在外部类加载时被加载

package testSingletonUnderMultiThreads;

/**
 * @author zhangdi
 * 使用静态内部类 
 * 静态内部类虽然保证了单例在多线程并发下的线程安全性,但是在遇到序列化对象时,默认的方式运行得到的结果就是多例的。
 */
public class Singleton_5_MyObject {
    //静态内部类的加载不需要依附外部类,在使用时才加载,而不是在外部类加载时被加载
    private static class MyObjectHandler {
        private static Singleton_5_MyObject myObject = new Singleton_5_MyObject();
    }
    //私有构造器是必须的
    private Singleton_5_MyObject() {
    }

    public static Singleton_5_MyObject getInstance() {
        return MyObjectHandler.myObject;

    }
}

6.序列化与反序列化的单例模式实现

package testSingletonUnderMultiThreads;

import java.io.ObjectStreamException;
import java.io.Serializable;

/**
 * @author zhangdi
 * 序列化与反序列化的单例模式实现
 */
public class Singleton_6_MyObject implements Serializable {
    private static final long serialVersionUID = 1L;

    private static class MyObjectHandler {
        private static Singleton_6_MyObject myObject = new Singleton_6_MyObject();
    }

    private Singleton_6_MyObject() {
    }

    public static Singleton_6_MyObject getInstance() {
        return MyObjectHandler.myObject;

    }

    // 该方法在反序列化时会被调用,该方法不是接口定义的方法,有点儿约定俗成的感觉
    protected Object readResolve() throws ObjectStreamException {
        System.out.println("调用了readResolve方法!");
        return MyObjectHandler.myObject;
    }

}

序列化与反序列化测试代码 :

package testSingletonUnderMultiThreads;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * @author zhangdi
 * 序列化与反序列化测试代码
 */
public class SaveAndReadForSingleton {

    public static void main(String[] args) {
        Singleton_6_MyObject singleton = Singleton_6_MyObject.getInstance();

        File file = new File("MySingleton.txt");

        try {
            FileOutputStream fos = new FileOutputStream(file);
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(singleton);
            fos.close();
            oos.close();
            System.out.println(singleton.hashCode());
        } catch (FileNotFoundException e) { 
            e.printStackTrace();
        } catch (IOException e) { 
            e.printStackTrace();
        }

        try {
            FileInputStream fis = new FileInputStream(file);
            ObjectInputStream ois = new ObjectInputStream(fis);
            Singleton_6_MyObject rSingleton = (Singleton_6_MyObject) ois.readObject();
            fis.close();
            ois.close();
            System.out.println(rSingleton.hashCode());
        } catch (FileNotFoundException e) { 
            e.printStackTrace();
        } catch (IOException e) { 
            e.printStackTrace();
        } catch (ClassNotFoundException e) { 
            e.printStackTrace();
        }

    }
}

7.static代码块实现单例

package testSingletonUnderMultiThreads;

/**
 * @author zhangdi
 * 使用static代码块实现单例,也可以保证线程安全性,也有资源占用问题
 */
public class Singleton_7_MyObject {
    private static Singleton_7_MyObject MyObject = null;

    private Singleton_7_MyObject(){}

    static {
        MyObject = new Singleton_7_MyObject();
    }

    public static Singleton_7_MyObject getInstance() {
        return MyObject;
    }

}

8.枚举实现单例模式

package testSingletonUnderMultiThreads;

/**
 * @author zhangdi
 * 使用枚举  缺点 : 但是这样写枚举类的实现细节被完全暴露了,违反了“职责单一原则”?
 */
public enum Singleton_8_MyObject_enum1 {
    singletonFactory;

    private MySingleton instance;

    private Singleton_8_MyObject_enum1(){//枚举类的构造方法在类加载是被实例化
        instance = new MySingleton();
    }

    public MySingleton getInstance(){
        return instance;
    }

}

class MySingleton{//需要获实现单例的类,比如数据库连接Connection
    public MySingleton(){} 
}

9.完善的枚举类实现单例模式

package testSingletonUnderMultiThreads;

/**
 * @author zhangdi
 * 完善使用enum枚举实现单例模式:不暴露枚举类的实现细节  
 */
public class Singleton_9_MyObject_enum2 {
    //不暴露枚举类的实现细节
    private enum MyEnumSingleton {
        singletonFactory;

        private MySingleton2 instance;

        private MyEnumSingleton() {// 枚举类的构造方法在类加载时被实例化
            instance = new MySingleton2();
        }

        public MySingleton2 getInstance() {
            return instance;
        }
    }

    public static MySingleton2 getInstance() {
        return MyEnumSingleton.singletonFactory.getInstance();
    }

}

class MySingleton2 {// 需要获实现单例的类,比如数据库连接Connection
    public MySingleton2() {
    }
}
posted @ 2018-07-11 10:46  XueXueLai  阅读(97)  评论(0编辑  收藏  举报