理解重排序

重排序通常是编译器或运行时环境为了优化程序性能而采取的对指令进行重新排序执行的一种手段。重排序分为两类:编译期重排序运行期重排序,分别对应编译时和运行时环境。

在并发程序中,程序员会特别关注不同进程或线程之间的数据同步,特别是多个线程同时修改同一变量时,必须采取可靠的同步或其它措施保障数据被正确地修改,这里的一条重要原则是:不要假设指令执行的顺序,你无法预知不同线程之间的指令会以何种顺序执行。

但是在单线程程序中,通常我们容易假设指令是顺序执行的,否则可以想象程序会发生什么可怕的变化。理想的模型是:各种指令执行的顺序是唯一且有序的,这个顺序就是它们被编写在代码中的顺序,与处理器或其它因素无关,这种模型被称作顺序一致性模型,也是基于冯·诺依曼体系的模型。当然,这种假设本身是合理的,在实践中也鲜有异常发生,但事实上,没有哪个现代多处理器架构会采用这种模型,因为它是在是太低效了。而在编译优化和CPU流水线中,几乎都涉及到指令重排序。 继续阅读

浅析Java虚拟机结构与机制

本文旨在给所有希望了解JVM(Java Virtual Machine)的同学一个概念性的入门,主要介绍了JVM的组成部分以及它们内部工作的机制和原理。当然本文只是一个简单的入门,不会涉及过多繁杂的参数和配置,感兴趣的同学可以做更深入的研究,在研究JVM的过程中会发现,其实JVM本身就是一个计算机体系结构,很多原理和我们平时的硬件、微机原理、操作系统都有十分相似的地方,所以学习JVM本身也是加深自我对计算机结构认识的一个很好的途径。

另外需要注意的是,虽然平时我们用的大多是Sun(现已被Oracle收购)JDK提供的JVM,但是JVM本身是一个规范,所以可以有多种实现,除了Hotspot外,还有诸如Oracle的JRockit、IBM的J9也都是非常有名的JVM。 继续阅读

CosHtmlCache静态化的自动化访问

为了提升访问速度并利于SEO,博主的博客使用CosHtmlCache插件进行静态化处理,该插件的一个不足就是就是必须在非登录状态下访问页面才会自动生成缓存,在后台的插件设置中只有删除缓存而没有一次性静态化的选项,这非常不方便,特别是当博文比较多达到几百篇时,显然人工点击是让人无法忍受的。

第一个想到的是直接修改插件,对文章内容进行变更后自动生成缓存,但是这里有一个问题:如果插件升级,就必须重新修改代码,另一方面这也破坏了封装原则。

鉴于此,我写了两个程序尝试解决这个问题,思路是用程序模拟GET请求自动访问所有页面,这样达到了与人工点击一样的效果。至于如何得到博客的所有文章和所有页面的地址,我使用了Google Sitemap XML插件。当然并不是单纯为了得到网址才安装的这个插件,之前为了优化Google的搜索,用这个插件自动生成了Sitemap然后在Google的Webmaster Tools里提交就可以起到比较好的收录效果。这个插件当然也可以提供博客所有的网址。

Java版本采用DOM对XML文件进行处理,PHP版本采用正则表达式解析出网址。 继续阅读

浅谈多态机制的意义及实现

在面向对象编程(Object-Oriented Programming, OOP)中,多态机制无疑是其最具特色的功能,甚至可以说,不运用多态的编程不能称之为OOP。这也是为什么有人说,使用面向对象语言的编程和面向对象的编程是两码事。

多态并没有一个严格的定义,维基百科上给它下的定义比较宽松:

Subtype polymorphism, almost universally called just polymorphism in the context of object-oriented programming, is the ability of one type, A, to appear as and be used like another type, B.

一、子类型和子类

这里我想先提一下子类型(Subtype)这个词和子类(Subclass)的区别,简单地说,只要是A类运用了extends关键字实现了对B类的继承,那么我们就可以说Class A是Class B的子类,子类是一个语法层面上的词,只要满足继承的语法,就存在子类关系。 继续阅读

采用Builder模式构造对象

通常构造对象时,我们会采用构造函数的方式来对对象的参数进行初始化,例如:

Student stu = new Student(2010, "Hesey", 0, 10, "Software College");

但这种方式带来的问题是可读性很差,程序员必须很清楚构造函数中各个参数是什么及其顺序,如果光看上面这条语句,程序员或许会知道这可能是在创建一个学生对象并作其参数的初始化,但是参数究竟意味着什么,就必须去看源代码或是查阅文档了。

所幸的是,JavaBeans规范给我们提供了一个可读性更强的解决方案,通过一连串的get,set方法对参数进行获取或设置,此时对Student的创建可以改为如下代码:

Student stu = new Student();
stu.setId(2010);
stu.setName("Hesey");
stu.setSex(0);
stu.setDoor(10);
stu.setAddress("Software College");

运用JavaBeans的这种方式,大大增强了对象参数初始化的可读性,程序员很清楚地可以知道正在设置的是什么参数,并且不必遵循类似构造函数那样的参数顺序。

问题在于,在对对象初始化的过程中,显而易见,各个参数的初始化被放到了不同的方法调用中,这会导致严重的线程不安全问题(构造函数则不存在这个问题)。对象在一连串的set方法中,可能会出现状态不一致的情况,这是应该尽量避免的。 继续阅读