Java 中 再一次看单例模式
来源:互联网 发布:淘宝可以用什么支付 编辑:程序博客网 时间:2024/04/30 19:59
还是那家伙,上一次看了我的博客说我 没理解单例模式,当时很郁闷,虽然我当时知道我没理解单例模式,但是很郁闷 很纠结,为啥还是不懂呢,现在总结一下找找问题,再一次反击他 .
我感觉单例模式 就是类只能有一个对象,我能想到的就是把这个类的构造函数定义成private 应该就可以了,然后外界不能访问他,怎么办? 可以给他们提供一个接口,返回这个类的方法,这样他们就可以用这个方法了,但是不能构造对象了.
<span style="font-size:14px;">class Test{private static final Test t = new Test();private Test(){}public static Test getTest(){return t;}}</span>
哈哈哈,无论别人调用多少次getTest其实这个类就一个对象,这样就实现了单例模式.
但是再一想不对啊,不管用不用这个对象肯定会被创建的,如果不用也创建就不是很好了,费时费内存
<span style="font-size:14px;">class Test{private static Test t = null;private Test(){}public static Test getTest(){if (t == null)t = new Test();return t;}}</span>
这样就好了,null 就重新创建,不为null就不用创建了,多省事.
但是还是不行又有了线程同步问题,万一线程A走到if里面还没有new,但是线程B运行了并且判断了t为null,这个时候B也进if里面了,这个时候就有了两个对象了不是单例模式了,但是仔细一想 不就是线程同步问题吗,好解决,方法前面用synchronized修饰就行了,加上同步锁,OK解决了.
但是上面的胡能胡能菜鸟还行,大牛一看就大发雷霆了,这TMD的效率不慢死啊,仔细一想也是, StringBuilder 和 StringBuffer 就知道了,synchronized这哥们效率低.
为了兼容效率和正确性,只能代码块同步了,这样好点,代码如下:
<span style="font-size:14px;">class Test{private static Test t = null;private Test(){}public static Test getTest(){if (t == null){synchronized(Test.class){if (t == null)t = new Test();}}return t;}}</span>
这样就OK了.
但是但是
下面我们开始说编译原理。所谓编译,就是把源代码“翻译”成目标代码——大多数是指机器代码——的过程。针对Java,它的目标代码不是本地机器代码,而是虚拟机代码。编译原理里面有一个很重要的内容是编译器优化。所谓编译器优化是指,在不改变原来语义的情况下,通过调整语句顺序,来让程序运行的更快。这个过程成为reorder。
要知道,JVM只是一个标准,并不是实现。JVM中并没有规定有关编译器优化的内容,也就是说,JVM实现可以自由的进行编译器优化。
下面来想一下,创建一个变量需要哪些步骤呢?一个是申请一块内存,调用构造方法进行初始化操作,另一个是分配一个指针指向这块内存。这两个操作谁在前谁在后呢?JVM规范并没有规定。那么就存在这么一种情况,JVM是先开辟出一块内存,然后把指针指向这块内存,最后调用构造方法进行初始化。
下面我们来考虑这么一种情况:线程A开始创建SingletonClass的实例,此时线程B调用了getInstance()方法,首先判断instance是否为null。按照我们上面所说的内存模型,A已经把instance指向了那块内存,只是还没有调用构造方法,因此B检测到instance不为null,于是直接把instance返回了——问题出现了,尽管instance不为null,但它并没有构造完成,就像一套房子已经给了你钥匙,但你并不能住进去,因为里面还没有收拾。此时,如果B在A将instance构造完成之前就是用了这个实例,程序就会出现错误了!
以上这段不是太懂,再说吧。。。应该是这样的.......
但是解决方案就是这样的
<span style="font-size:14px;">class Test{private volatile static Test t = null;private Test(){}public static Test getTest(){if (t == null){synchronized(Test.class){if (t == null)t = new Test();}}return t;}}</span>
就是使用了volatile修饰符JDK1.5才用的.
- Java 中 再一次看单例模式
- 再一次读 工厂模式
- java中图片按质量压缩的再一次小结
- 再一次接触JAVA
- 中石油的再一次爆发
- 再一次,开始我的Java学习
- 再一次认识到C函数中参数传递:传值。
- 学Java三月半后的再一次回头
- 再一次 - Java的引用传递与值传递
- 再一次和好
- 再一次回来
- 再一次开始
- 再一次创业
- 再一次决心
- 再一次测试
- Java中路由器模式
- java中设计模式
- java中设计模式
- Java:重写equals()和hashCode()
- 为什么是Createthread后要CloseHandle
- VBA清除Excel密码保护,2003/2007/2010均适用
- C\C++小知识:C\C++中#define和inline的区别
- Path Sum--路径和(重)
- Java 中 再一次看单例模式
- ios返回当前时间,精确到毫秒。
- 黑马程序员_java中IO流的操作规律
- C++调用lua函数的一种通用办法
- servlet、genericservlet、httpservlet之间的区别
- Android中Activity、Service和线程之间的通信
- DFS IDFS 离散傅里叶级数
- POJ2876——递归
- gradle2.0笔记——让项目升级到gradle2.0