Java单例模式与多线程
来源:互联网 发布:淘宝代码装修教程 编辑:程序博客网 时间:2024/05/19 15:19
该篇博客,将会通过单例模式和多线程技术相结合的方式来学习,在此期间,我们会遇到之前没有考虑过的情况,那么,废话不多说,先来看看,实现单例模式的两种方法
饿汉模式
public class MyObjectHungery { private static MyObjectHungery sMyObject = new MyObjectHungery(); private MyObjectHungery() { } public static MyObjectHungery getMyObjectInstance() { return sMyObject; }}
懒汉模式
public class MyObjectLazy { private static MyObjectLazy sMyObject = null; private MyObjectLazy() { } public static MyObjectLazy getMyObjectInstance() { if (sMyObject == null) { sMyObject = new MyObjectLazy(); } return sMyObject; }}
懒汉和饿汉模式的缺点
上面虽然使用”立即加载”和”延迟加载”实现了单例设计模式,但是在多线程下,根本不能实现 保持単例的状态。看下面的代码:
public class MyObjectLazy { private static MyObjectLazy sMyObject = null; private MyObjectLazy() { } public static MyObjectLazy getMyObjectInstance() { try { if (sMyObject == null) { // 懒汉模式,模拟创建对象时候的一些耗时操作 Thread.sleep(3000); sMyObject = new MyObjectLazy(); } } catch (InterruptedException e) { e.printStackTrace(); } return sMyObject; } private static class MyThread extends Thread{ @Override public void run() { super.run(); // 通过懒汉模式获得当前単例对象,并打印其hashCode System.out.println("current object is : "+MyObjectLazy.getMyObjectInstance().hashCode()); } } public static void main(String[] args) { // 模拟多线程环境下,通过打印当前对象的hashCode,判断懒汉模式存在的多线程问题 MyThread t1 = new MyThread(); MyThread t2 = new MyThread(); MyThread t3 = new MyThread(); t1.start(); t2.start(); t3.start(); }}
此时打印结果如下:
懒汉模式的解决方案
- 声明synchronized关键字
public synchronized static MyObjectLazy getMyObjectInstance() { try { if (sMyObject == null) { // 懒汉模式,模拟创建对象时候的一些耗时操作 Thread.sleep(3000); sMyObject = new MyObjectLazy(); } } catch (InterruptedException e) { e.printStackTrace(); } return sMyObject;}
此时程序运行结果:
可以看到我们在此方法上加入了synchronized关键字得到相同实例对象,但是这种方法的运行效率非常低下,是同步运行的,下一个线程想要取得对象,就必须要等到上一个线程释放锁之后,才可以。
- 同步代码块来解决
同步代码块可以针对某些重要的代码进行单独同步,而其他代码不需要同步,这样可以大幅提升效率。
public static MyObjectLazy getMyObjectInstance() { try { if (sMyObject == null) { // 懒汉模式,模拟创建对象时候的一些耗时操作 Thread.sleep(3000); synchronized (MyObjectLazy.class) { if (sMyObject == null) { sMyObject = new MyObjectLazy(); } } } } catch (InterruptedException e) { e.printStackTrace(); } return sMyObject; }
使用静态内部类实现单例模式
public class MyObjectStatic { private static class GetStaticObj { private static MyObjectStatic sMyObjectStatic = new MyObjectStatic(); } private MyObjectStatic() { } public static MyObjectStatic getMyObjectInstance() { return GetStaticObj.sMyObjectStatic; }}
序列化与反序列化的単例模式
上面的代码,使用静态内部类虽然可以达到线程安全,但是如果遇到序列化和反序列化对象时候,还是多例的。看下面代码:
public class MyObjectStatic implements Serializable{ private static final long serialVersionUID = -4956049192964237265L; private static class GetStaticObj { private static MyObjectStatic sMyObjectStatic = new MyObjectStatic(); } private MyObjectStatic() { } public static MyObjectStatic getMyObjectInstance() { return GetStaticObj.sMyObjectStatic; } private static class MyThread extends Thread{ @Override public void run() { super.run(); // 通过懒汉模式获得当前単例对象,并打印其hashCode System.out.println("current object is : "+MyObjectStatic.getMyObjectInstance().hashCode()); } } public static void main(String[] args) { // 将获得的単例模式序列化对象写入到文件里,并打印其hashcode try { MyObjectStatic myObjectStatic = MyObjectStatic.getMyObjectInstance(); OutputStream os = new FileOutputStream(new File("D:/object.txt")); ObjectOutputStream oos = new ObjectOutputStream(os); oos.writeObject(myObjectStatic); os.close(); oos.close(); System.out.println("myObjectStatic write is :"+myObjectStatic.hashCode()); } catch (Exception e) { e.printStackTrace(); } // 从文件里读取写入的学序列化単例对象,并打印其hashcode try { InputStream is = new FileInputStream(new File("D:/object.txt")); ObjectInputStream ois = new ObjectInputStream(is); MyObjectStatic myObjectStatic = (MyObjectStatic) ois.readObject(); is.close(); ois.close(); System.out.println("myObjectStatic read is :"+myObjectStatic.hashCode()); } catch (Exception e) { e.printStackTrace(); } }}
可以看到,这里我们写入和读取的是不同的对象。
这里,我们在単例类中加入下面代码:
// 在反序列化中使用readResolve方法private Object readResolve() { System.out.println("readResolve method runs ......"); return GetStaticObj.sMyObjectStatic; }
此时效果如下:
0 0
- 【转】JAVA 单例模式与多线程
- JAVA 单例模式与多线程
- JAVA 单例模式与多线程
- Java单例模式与多线程
- java 单例模式与多线程
- Java多线程编程核心技术---单例模式与多线程
- Java多线程核心技术(六):单例模式与多线程
- java多线程编程核心技术6-单例模式与多线程
- Java多线程编程6--单例模式与多线程--单例模式
- Java多线程编程6--单例模式与多线程--单例模式设计详解1
- 单例模式与多线程
- 单例模式与多线程
- 单例模式与多线程
- 单例模式与多线程
- 单例模式与多线程
- 单例模式与多线程
- 单例模式与多线程
- 单例模式与多线程
- 修改grub2默认启动顺序
- c++中vector的用法详解
- Power of Three
- 结合开发文档分析volley(二)
- SG函数
- Java单例模式与多线程
- 读书笔记-陆-《从你的全世界路过》
- 码神作业(九九乘法表)
- Android 6.0特性
- 递归
- Partition List
- ZYNQ Z-TURN BOARD 学习笔记1-Ubuntu上的流水灯实验
- tomcat点击startup.bat一闪而过
- HDU 5748 (Bellovin LIS)