饿汉模式又称为当即加载模式,含以上就是很是急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(); } } }