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的任務管理器,打不開兩個。 網站的計數器,不然很難實現同步。 數據庫連接池的設計