1. 程式人生 > >java設計模式——單例模式(三)

java設計模式——單例模式(三)

容器單例模式

之前學習Structs2,Spring框架時,經常會聽到單例,多例。雖然這與單例模式不太一樣,但是都很類似。在程式執行的時候,就載入所有的例項,然後用的時候直接取出

看下面程式碼:

/**
 * @program: designModel
 * @description: 容器單例模式
 * @author: YuKai Fan
 * @create: 2018-12-11 14:59
 **/
public class ContaineSingleton {
    private ContaineSingleton() {}
    private static Map<String, Object> singletonMap = new
HashMap<String, Object>(); public static void putInstance(String key, Object instance) { if (StringUtils.isNotBlank(key) && instance != null) { if (!singletonMap.containsKey(key)) { singletonMap.put(key, instance); } } }
public static Object getInstance(String key) { return singletonMap.get(key); } }

但是,這種方式在不考慮序列化與反射的情況下,依舊是不安全的。因為在多執行緒的環境下,還是會產生不同的例項,這需要結合場景來使用。

如果使用hashTable來保證執行緒安全的話,效率會很低,頻繁去取例項都回家加同步鎖。如果使用ConcurrentHashMap,由於被static修飾,相當於直接操作了 map,在這種場景下,也不是絕對的執行緒安全。

ThreadLocal環境下的"單例模式"

這種帶引號的單例模式,並不是真正的單例模式。因為並不能保證整個應用只產生一個例項,只會保證整個應用執行緒唯一

/**
 * @program: designModel
 * @description:
 * @author: YuKai Fan
 * @create: 2018-12-11 15:17
 **/
public class ThreadLocalInstance {
    private static final ThreadLocal<ThreadLocalInstance> threadLocalInstance = new ThreadLocal<ThreadLocalInstance>(){
        @Override
        protected ThreadLocalInstance initialValue() {
            return new ThreadLocalInstance();
        }
    };
    private ThreadLocalInstance() {}

    public static ThreadLocalInstance getInstance() {
        return threadLocalInstance.get();
    }

}
/**
 * @program: designModel
 * @description:
 * @author: YuKai Fan
 * @create: 2018-12-04 14:11
 **/
public class T implements Runnable {
    public void run() {

        ThreadLocalInstance instance = ThreadLocalInstance.getInstance();
        System.out.println(Thread.currentThread().getName() + "" + instance);

    }
}
/**
 * @program: designModel
 * @description:
 * @author: YuKai Fan
 * @create: 2018-12-04 14:07
 **/
public class Test {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
//        LazySingleton lazySingleton = LazySingleton.getInstance();
        Thread t1 = new Thread(new T());
        Thread t2 = new Thread(new T());
        t1.start();
        t2.start();
        System.out.println("測試");
    }
}

輸出結果:

產生的是不同的例項,但是ThreadLocal回味每個執行緒提供獨立的變數副本,將每個執行緒的例項隔離。保證在多執行緒的情況下,會保證每個執行緒只能產生一個例項

單例模式原始碼分析

單例模式在jdk下的應用:

java.lang.Runtime下的getRuntime()方法,屬於餓漢式

AWT下的Desktop類中的getDesktop()