Java 單例設計模式 常見4種

Java 單例設計模式 常見4種
適合功能場景
主要特色
餓漢式單例 Eager loading(當即加載方式)
懶漢式單例 Lazy Loading(延遲加載方式)
枚舉單例
ConcurrentHashMap容器單例
適合功能場景
配置文件讀寫對象, 數據庫鏈接池, Spring的 IOC容器 ApplicationContext, Windows的任務管理/回收站等
主要特色
單例類只能實例化一次
提供惟一全局訪問入口來獲取該實例
餓漢式單例 Eager loading(當即加載方式)
項目啓動時類被加載, 對象與之同時實例化
除非項目重啓否者對象不會有變化, 也就是線程安全的web

public class EagerSingleton implements Serializable {
    private static final long serialVersionUID = 7073777279565036708L;數據庫

    private static volatile EagerSingleton instance = new EagerSingleton();設計模式

    /**
     * 爲了防止經過反射機制實例化構造方法拋異常
      /
    private EagerSingleton() {
        if(instance != null){
            throw new RuntimeException("不容許被反射實例化");
        }
    }安全

    public static EagerSingleton getInstance() {
        return instance;
    }測試

    /**
     * readResolve方法的做用爲防止序列化單例時破壞惟一實例的規則
      /
    private Object readResolve() throws ObjectStreamException {
        return instance;
    }this

}線程

public class App {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(() -> {
                System.out.println("EagerSingleton > " + Thread.currentThread().getName() + " > " + EagerSingleton.getInstance());
            });
            thread.start();
        }
    }設計

}對象

EagerSingleton > Thread-0 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-1 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-2 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-3 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-4 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-5 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-6 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-7 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-8 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-9 > com.test.web4.singleton.EagerSingleton@6a3289caget

懶漢式單例 Lazy Loading(延遲加載方式)
類被加載時, 對象不被實例化. 此單例是經過類提供的全局訪問入口來獲取對象或實例化首個實例後獲取對象
注: 懶漢式因爲有線程安全問題必須作雙重檢查並加鎖

public final class LazySingleton implements Serializable {
    private static final long serialVersionUID = -5683703520820349246L;

    private static volatile LazySingleton instance = null;

    /**
     * 爲了防止經過反射機制實例化構造方法拋異常
      /
    private LazySingleton() {
        if (instance != null) {
            throw new RuntimeException("不容許被反射實例化");
        }
    }

    public static LazySingleton getInstance() {
        if (instance == null) {
            synchronized (LazySingleton.class) {
                                if(instance == null) {
                                        instance = new LazySingleton();
                                }
            }
        }
        return instance;
    }

    /**
     * readResolve方法的做用爲防止序列化單例時破壞惟一實例的規則
      /
    private Object readResolve() throws ObjectStreamException {
        return instance;
    }

}

public class App {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(() -> {
                System.out.println("LazySingleton > " + Thread.currentThread().getName() + " > " + LazySingleton.getInstance());
            });
            thread.start();
        }
    }

}

LazySingleton > Thread-0 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-1 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-2 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-3 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-4 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-5 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-6 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-7 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-8 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-9 > com.test.web4.singleton.LazySingleton@5e5035fb

枚舉單例
Java虛擬機默認防止了枚舉類型的序列化和反射破壞, 因此構造方法無需拋異常以及無需加 readResolve方法

public enum EnumSingleton {
    INSTENCE;

    private EnumSingleton() {}

    private Object data;

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public static EnumSingleton getInstance() {
        return INSTENCE;
    }

}

public class App {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(() -> {
                System.out.println("EnumSingleton > " + Thread.currentThread().getName() + " > " + EnumSingleton.getInstance());
            });
            thread.start();
        }
    }

}

EnumSingleton > Thread-0 > INSTENCE
EnumSingleton > Thread-1 > INSTENCE
EnumSingleton > Thread-2 > INSTENCE
EnumSingleton > Thread-3 > INSTENCE
EnumSingleton > Thread-4 > INSTENCE
EnumSingleton > Thread-5 > INSTENCE
EnumSingleton > Thread-6 > INSTENCE
EnumSingleton > Thread-7 > INSTENCE
EnumSingleton > Thread-8 > INSTENCE
EnumSingleton > Thread-9 > INSTENCE

ConcurrentHashMap容器單例
經過 ConcurrentHashMap管理多個對象, 雖然它自己是線程安全的但獲取實例的方法不是, 因此須要使用同步鎖

public class ContainerSingleton {
    private ContainerSingleton() {}

    private static Map<String,Object> ioc = new ConcurrentHashMap<>();

    public static Object getBean(final String className) {
        if (className != null && !"".equals(className)) {
            synchronized (className) {
                if (ioc.containsKey(className)) {
                    return ioc.get(className);
                }
                Object obj = null;
                try {
                    obj = Class.forName(className).newInstance();
                    ioc.put(className,obj);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return obj;
            }
        }
        return null;
    }

}

/**

  • 此測試類需經過反射機制實例化, 因此必須有無參構造方法
  • */

public class TestA {
    private Integer id;
    private String name;

    public TestA() {}

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public class App {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(() -> {
                System.out.println("ContainerSingleton > " + Thread.currentThread().getName() +
                        " > " + ContainerSingleton.getBean("com.test.web4.singleton.TestA"));
            });
            thread.start();
        }
    }

}

ContainerSingleton > Thread-0 > com.test.web4.singleton.TestA@6d559005ContainerSingleton > Thread-1 > com.test.web4.singleton.TestA@6d559005ContainerSingleton > Thread-2 > com.test.web4.singleton.TestA@6d559005ContainerSingleton > Thread-3 > com.test.web4.singleton.TestA@6d559005ContainerSingleton > Thread-4 > com.test.web4.singleton.TestA@6d559005ContainerSingleton > Thread-5 > com.test.web4.singleton.TestA@6d559005ContainerSingleton > Thread-6 > com.test.web4.singleton.TestA@6d559005ContainerSingleton > Thread-7 > com.test.web4.singleton.TestA@6d559005ContainerSingleton > Thread-8 > com.test.web4.singleton.TestA@6d559005ContainerSingleton > Thread-9 > com.test.web4.singleton.TestA@6d559005

相關文章
相關標籤/搜索