餓漢模式又稱爲當即加載模式,含以上就是很是急java
也就是在使用類的時候已經將對象建立完畢設計模式
package lock; public class EhanSingleton { /*餓漢加載模式/當即加載模式*/ //初始化構造函數 private EhanSingleton(){ } private static EhanSingleton ehan = new EhanSingleton(); public static EhanSingleton getInstance(){ try { Thread.sleep(3000); //方便多線程測試 } catch (InterruptedException e) { e.printStackTrace(); } return ehan ; } }
而後咱們用簡單的多線程測試多線程
package lock; public class MyThread extends Thread{ @Override public void run() { System.out.println(EhanSingleton.getInstance().hashCode()); } public static void main(String[] args) { MyThread m1 = new MyThread(); MyThread m12 = new MyThread(); MyThread m13 = new MyThread(); m1.start(); m12.start(); m13.start(); } }
126720696ide
126720696
126720696函數
算出來的結果每一個對象的 hashcode的值是同樣的,說明這個模式是符合單例模式的,這個也就是當即加載型單例設計模式測試
第二種單例模式 懶漢模式/延遲加載spa
這個方式是隻有調用某個方法的時候才能調用這個實例線程
package lock; public class LanHanSingleton { /*懶漢模式/延遲加載*/ //私有化構造函數 private LanHanSingleton(){ } private static LanHanSingleton lanHanSingleton ; public static LanHanSingleton getInstance() { if(lanHanSingleton == null){ try { Thread.sleep(3000); lanHanSingleton = new LanHanSingleton() ; } catch (InterruptedException e) { e.printStackTrace(); } } return lanHanSingleton ; } }
我在用多線程去測試一下是否每一個對象的HashCode的值是保持一致的設計
package lock; public class MyThread extends Thread{ @Override public void run() { System.out.println(LanHanSingleton.getInstance().hashCode()); } public static void main(String[] args) { MyThread m1 = new MyThread(); MyThread m12 = new MyThread(); MyThread m13 = new MyThread(); m1.start(); m12.start(); m13.start(); } }
126720696
137014984
1638443495code
測試的結果發現 這個已經不符合單例模式,他們並非同一個對象了,而是幾個不一樣的對象,因此這種懶漢模式在單線程中是符合單例模式的,不過在多線程環境中是不符合單例模式
想到這裏,你們確定會想到了synchrinized關鍵字,咱們在來看看效果
package lock; public class LanHanSingleton { /*懶漢模式/延遲加載*/ //私有化構造函數 private LanHanSingleton(){ } private static LanHanSingleton lanHanSingleton ; public synchronized static LanHanSingleton getInstance() { if(lanHanSingleton == null){ try { Thread.sleep(3000); lanHanSingleton = new LanHanSingleton() ; } catch (InterruptedException e) { e.printStackTrace(); } } return lanHanSingleton ; } }
運行結果:
1638443495
1638443495
1638443495
你們發現這樣的確能夠解決多線程帶來的不一樣對象所致使的問題,可是這個方法並很差,這種方法效率很是低下,必定要等到上一個線程釋放鎖之後才能獲取對象
同步方法是對整個方法持有鎖,這個對於效率來講實在太慢,你們還會想到用同步塊,那麼咱們在試一試
package lock; public class LanHanSingleton { /*懶漢模式/延遲加載*/ //私有化構造函數 private LanHanSingleton(){ } private static LanHanSingleton lanHanSingleton ; public static LanHanSingleton getInstance() { try { synchronized (LanHanSingleton.class) { if(lanHanSingleton == null){ Thread.sleep(3000); lanHanSingleton = new LanHanSingleton() ; } } } catch (InterruptedException e) { e.printStackTrace(); } return lanHanSingleton ; } }
其實這個效果和上個效果差很少,效率都是比較慢的,和同步方法synchronized同樣是同步運行的
這裏最好的方式就是DCL雙檢查鎖機制
package lock; public class LanHanSingleton { /*懶漢模式/延遲加載*/ //私有化構造函數 private LanHanSingleton(){ } private static LanHanSingleton lanHanSingleton ; public static LanHanSingleton getInstance() { try { if(lanHanSingleton == null){ synchronized (LanHanSingleton.class) { if(lanHanSingleton == null){ lanHanSingleton = new LanHanSingleton() ; } } } } catch (InterruptedException e) { e.printStackTrace(); } return lanHanSingleton ; } }
還有一種的就是內部類的方式
package lock; import java.io.ObjectStreamException; import java.io.Serializable; public class MyObject implements Serializable{ private MyObject(){ } private static class MyObjectHander{ private static MyObject myObject = new MyObject(); } public static MyObject getInstance(){ return MyObjectHander.myObject; } // public MyObject readResolve() throws ObjectStreamException { // System.out.println("這個方法被調用了"); // return MyObjectHander.myObject; // } }
這個是內部類的方式,不過這個內部的方式仍是有存在問題的肯能,這個雖然能夠達到多線程單例模式的狀況,不過若是遇到序列化的狀況下就會違反單例模式的準則。。。。。
註釋的方法就是爲了序列化所提供的
package lock; import java.io.ObjectStreamException; import java.io.Serializable; public class MyObject implements Serializable{ private static final long serialVersionUID = 1L; private MyObject(){ } private static class MyObjectHander{ private static final MyObject myObject = new MyObject(); } public static MyObject getInstance(){ return MyObjectHander.myObject; } protected MyObject readResolve() throws ObjectStreamException { System.out.println("這個方法被調用了"); return MyObjectHander.myObject; } }
package lock; 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; public class CheckSingletonHashCode { public static void main(String[] args) { try { MyObject myObject = MyObject.getInstance(); FileOutputStream os = new FileOutputStream(new File("D://lol.txt")); ObjectOutputStream oos = new ObjectOutputStream(os); oos.writeObject(myObject); oos.close(); os.close(); System.out.println(myObject.hashCode()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } try { FileInputStream is = new FileInputStream(new File("D://lol.txt")); ObjectInputStream ois = new ObjectInputStream(is); MyObject myObject = (MyObject) ois.readObject(); ois.close(); is.close(); System.out.println(myObject.hashCode()); } catch (FileNotFoundException e) { e.printStackTrace(); }catch (ClassNotFoundException | IOException e) { e.printStackTrace(); } } }