首页 > 代码库 > 单例模式 和 多线程
单例模式 和 多线程
饿汉模式又称为立即加载模式,含以上就是非常急
也就是在使用类的时候已经将对象创建完毕
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(); }}
126720696
126720696
126720696
算出来的结果每个对象的 hashcode的值是一样的,说明这个模式是符合单例模式的,这个也就是立即加载型单例设计模式
第二种单例模式 懒汉模式/延迟加载
这个方式是只有调用某个方法的时候才能调用这个实例
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
1638443495
测试的结果发现 这个已经不符合单例模式,他们并不是同一个对象了,而是几个不同的对象,所以这种懒汉模式在单线程中是符合单例模式的,不过在多线程环境中是不符合单例模式
想到这里,大家肯定会想到了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(); } }}
单例模式 和 多线程