單例模式的各種寫法和總結 懶漢式 餓漢式 登記式


public class Singleton {//懶漢式單例類
/**
 懶漢式單例類。   只在外部對象第一次請求實例的時候才會去創建
     優點:第一次調用時才會初始化,避免內存浪費。
    缺點:必須加鎖synchronized 才能保證單例
 */
  private static volatile Singleton singleton;// !!必須要加volatile限制指令重排序,不然這是雙重檢驗的漏洞
    private static final ReentrantLock lock = new ReentrantLock();
    private static AtomicInteger count=new AtomicInteger(0);
    private Singleton() {
        count.incrementAndGet();
    }

    public static synchronized  Singleton getInstance() {
    
        if (singleton == null) {
            lock.lock();
            if (singleton == null) { //雙重鎖定,防止幾個線程同時進入,eg:a進入,bc等待,a第一次實例化單例,b得到鎖后進入,
                                        //此處如不判斷,則b也會實例化單例,造成多次實例化。 但是多線程測試中沒出現這種情況
                singleton = new Singleton();
            }
            lock.unlock();
        }
        return singleton;
    }
    public void show(){
        System.out.println(count);
    }
    
    public static void main(String[] args) throws InterruptedException {
//        Singleton s1 = Singleton.getInstance();
//        Singleton s2 = Singleton.getInstance();
//        if (s1 == s2)
//            System.out.println("euqal");//equal
//        else {
//            System.out.println("not equal");
//        }
        
        ExecutorService service = Executors.newCachedThreadPool();
        for(int i=0;i<50;i++){
            Thread t =new Thread(new MyThread());
            service.execute(t);
        }

        Thread.sleep(5000);
        service.shutdown();
    }
}

class MyThread implements Runnable{

    @Override
    public void run() {
        Singleton s = Singleton.getInstance();
        s.show();
    }
    
}

 

餓漢式單例類

public class SingletonHungry {
public static void main(String[] args) throws InterruptedException {
    ExecutorService service = Executors.newCachedThreadPool();
    for(int i=0;i<30;i++){
        Thread t =new Thread(new MyThread2());
        service.execute(t);
    }

    Thread.sleep(1000);
    service.shutdown();
}
}
/*
       餓漢式單例類。    它在類加載時就立即創建對象。
       優點:沒有加鎖,執行效率高。  用戶體驗上來說,比懶漢式要好。
        缺點:類加載時就初始化,浪費內存
 */
class Singleton2{
    private static AtomicInteger count = new AtomicInteger(10);
    private static final Singleton2 SINGLETON = new Singleton2();
    private Singleton2(){
        count.incrementAndGet();
    }
    public static Singleton2 getInstance(){
        return SINGLETON;
    }
    public void show() {
        System.out.println(count);
    }
}
class MyThread2 implements Runnable{

    @Override
    public void run() {
        Singleton2 s2 = Singleton2.getInstance();
        s2.show();
    }
    
}

 

登記式模式

內部類只有在外部類被調用才加載,產生SINGLETON實例,又不用加鎖,此模式有上述倆模式的優點,屏蔽了他們的缺點,是 最好的單例模式。
public class Singleton{
    private Singleton(){}
    public static Singleton getInstance(){ return Holder.SINGLETON;}
    private static class Holder{//內部類
        private static final Singleton SINGLETON= new Singleton();
    }
}

 

單例類的特點:
1、單例類確保自己只有一個實例
2、單例類必須自己創建自己的實例
3、單例類必須為其他對象提供唯一的實例。

單例類的優點:

(1) 控制資源的使用,通過線程同步來控制資源的並發訪問。
(2)控制實例的產生數量,達到節約資源的目的。
(3)作為通信的媒介,數據共享。他可以在不建立直接關聯的條件下,讓多個不相關的兩個線程或者多個進程之間實現通信。

 

單例類實用舉例:Windows的任務管理器,打不開兩個。 網站的計數器,不然很難實現同步。   數據庫連接池的設計

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM