posts - 403, comments - 310, trackbacks - 0, articles - 7
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

     摘要: 以下简单的整理来自游侠 netshow论坛的帖子 部分补充  阅读全文

posted @ 2008-04-13 11:30 ZelluX 阅读(1044) | 评论 (1)编辑 收藏

     摘要: 问题:
给定n个32位无符号整数,求出其中异或结果最大的两个整数。  阅读全文

posted @ 2008-04-10 00:33 ZelluX 阅读(4631) | 评论 (5)编辑 收藏

转载请注明 作者 ZelluX    http://www.blogjava.net/zellux

看OOP教材时,提到了一个双检测锁定(Double-Checked Lock, DCL)的问题,但是书上没有多介绍,只是说这是一个和底层内存机制有关的漏洞。查阅了下相关资料,对这个问题大致有了点了解。

从头开始说吧。

在多线程的情况下Singleton模式会遇到不少问题,一个简单的例子

   1:  class Singleton {     
   2:      private static Singleton instance = null;     
   3:        
   4:      public static Singleton instance() {     
   5:          if (instance == null) {     
   6:              instance = new Singleton();     
   7:          }     
   8:          return instance;    
   9:      }    
   10:  }

  
假设这样一个场景,有两个线程调用Singleton.instance(),首先线程一判断instance是否等于null,判断完后一瞬间虚拟机把线程二调度为运行线程,线程二再次判断instance是否为null,然后创建一个Singleton实例,线程二的时间片用完后,线程一被唤醒,接下来它执行的代码依然是instance = new Singleton();
两次调用返回了不同的对象,出现问题了。

最简单的方法自然是在类被载入时就初始化这个对象:private static Singleton instance = new Singleton();

JLS(Java Language Specification)中规定了一个类只会被初始化一次,所以这样做肯定是没问题的。

但是如果要实现延迟初始化(Lazy initialization),比如这个实例初始化时的参数要在运行期才能确定,应该怎么做呢?

依然有最简单的方法:使用synchronized关键字修饰初始化方法:

    public synchronized static Singleton instance() {       
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }

   
这里有一个性能问题:多个线程同时访问这个方法时,会因为同步而导致每次只有一个线程运行,影响程序性能。而事实上初始化完毕后只需要简单的返回instance的引用就行了。

DCL是一个“看似”有效的解决方法,先把对应代码放上来吧:

    1 :   class Singleton {  
    2 :       private static Singleton instance = null ;  
    3 :     
    4 :       public static Singleton instance() {  
    5 :           if (instance == null ) {
    6 :               synchronized (this) {  
    7 :                   if (instance == null)
    8 :                      instance = new Singleton();
    9 :              }
    10 :          }
    11 :          return instance;
    12 :      }
    13 :  }

用JavaWorld上对应文章的标题来评论这种做法就是smart, but broken。来看原因:

Java编译器为了提高程序性能会进行指令调度,CPU在执行指令时同样出于性能会乱序执行(至少现在用的大多数通用处理器都是out-of-order的),另外cache的存在也会改变数据回写内存时的顺序[2]。JMM(Java Memory Model, 见[1])指出所有的这些优化都是允许的,只要运行结果和严格按顺序执行所得的结果一样即可。

Java假设每个线程都跑在自己的处理器上,享有自己的内存,和共享的主存交互。注意即使在单核上这种模型也是有意义的,考虑到cache和寄存器会保存部分临时变量。理论上每个线程修改自己的内存后,必须立即更新对应的主存内容。但是Java设计师们认为这种约束会影响程序性能,他们试着创造了一套让程序跑得更快、但又保证线程之间的交互与预期一致的内存模型。

synchronized关键字便是其中一把利器。事实上,synchronized块的实现和Linux中的信号量(semaphore)还是有区别的,前者过程中锁的获得和释放都会都会引发一次Memory Barrier来强制线程本地内存和主存之间的同步。通过这个机制,Java中的同步机制保证了synchronized块中指令的原子性(atomic)。

好了,回过头来看DCL问题。看起来访问一个未同步的instance字段不会产生什么问题,我们再次来假设一个场景:

线程一进入同步块,执行instance = new Singleton(); 线程二刚开始执行getResource();

按照顺序的话,接下来应该执行的步骤是 1) 分配新的Singleton对象的内存 2) 调用Singleton的构造器,初始化成员字段 3) instance被赋为指向新的对象的引用。

前面说过,编译器或处理器都为了提高性能都有可能进行指令的乱序执行,线程一的真正执行步骤可能是1) 分配内存 2) instance指向新对象 3) 初始化新实例。如果线程二在2完成后3执行前被唤醒,它看到了一个不为null的instance,跳出方法体走了,带着一个还没初始化的Singleton对象。

错误发生的一种情形就是这样,关于更详细的编译器指令调度导致的问题,可以参看这个网页 [4]。

[3] 中提供了一个编译器指令调度的证据

instance = new Singleton(); 这条命令在Symantec JIT中被编译成

0206106A   mov         eax,0F97E78h
0206106F   call        01F6B210                  ; 分配空间
02061074   mov         dword ptr [ebp],eax       ; EBP中保存了instance的地址

02061077   mov         ecx,dword ptr [eax]       ; 解引用,获得新的指针地址

02061079   mov         dword ptr [ecx],100h      ; 接下来四行是inline后的构造器
0206107F   mov         dword ptr [ecx+4],200h   
02061086   mov         dword ptr [ecx+8],400h
0206108D   mov         dword ptr [ecx+0Ch],0F84030h

可以看到,赋值完成在初始化之前,而这是JLS允许的。
 
另一种情形是,假设线程一安稳地完成Singleton对象的初始化,退出了同步块,并同步了和本地内存和主存。线程二来了,看到一个非空的引用,拿走。注意线程二没有执行一个Read Barrier,因为它根本就没进后面的同步块。所以很有可能此时它看到的数据是陈旧的。

还有很多人根据已知的几种提出了一个又一个fix的方法,但最终还是出现了更多的问题。可以参阅[3]中的介绍。

[5]中还说明了即使把instance字段声明为volatile还是无法避免错误的原因。

由此可见,安全的Singleton的构造一般只有两种方法,一是在类载入时就创建该实例,二是使用性能较差的synchronized方法。

(by ZelluX  http://www.blogjava.net/zellux )

参考资料:

[1] Java Language Specification, Second Edition, 第17章介绍了Java中线程和内存交互关系的具体细节。
[2] out-of-order与cache的介绍可以参阅Computer System, A Programmer's Perspective的第四、五章。
[3] The "Double-Checked Locking is Broken" Declaration, http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
[4] Synchronization and the Java Memory Model, http://gee.cs.oswego.edu/dl/cpj/jmm.html
[5] Double-checked locking: Clever, but broken, http://www.javaworld.com/javaworld/jw-02-2001/jw-0209-double.html?page=1
[6] Holub on Patterns, Learning Design Patterns by Looking at Code

 

posted @ 2008-04-07 21:58 ZelluX 阅读(2309) | 评论 (7)编辑 收藏

感冒发烧。

把不应该存在的博文全删了。

我知道我在和自己赌气。

那又如何。

回过头来,这两年我所得到的,不过是可以随手扔掉的东西。

最后,acm的那些人们加油。

posted @ 2008-04-06 14:05 ZelluX 阅读(326) | 评论 (3)编辑 收藏

翘课大半,作业一半不交一半抄,总之太不像学生了。
搞得现在Super Scalar都只知道个大概,tableaux也知其然而不知所以然。
下星期好好参与一次,上课、作业一个都不能少,恩。
至于之后么,再说咯。

posted @ 2008-04-04 15:33 ZelluX 阅读(391) | 评论 (0)编辑 收藏

没事干找了几个SICP上的习题做,先是一道以前只想出一种很啰嗦的写法的题目

Ex 2.18
把一个列表倒过来。不习惯在lisp里用iterative方式 >,<

接下来几题都是Map-Reduce思想的应用(或者照书上的说法,用enumerator - filter - map - accumulator这四个步骤操作一个list)

用到的几个函数:

enumrate-tree 的功能是遍历一个树状结构,把其中的所有叶子保存在一个list中。

Ex 2.34
利用Horner's rule计算多项式结果(这公式这几天还经常碰到)

Ex 2.35
数出一棵树中的叶子数。这题我的做法比较土,没想到map-reduce操作上的递归,而是把叶子节点的值都改成1然后一个累加。

其实只要递归调用主函数就行了

Ex 2.36
可以理解为计算矩阵各列之和吧


> (accumulate-n + 0 (list (list 1 2 3) (list 4 5 6) (list 7 8 9) (list 10 11 12)))
(22 26 30)

posted @ 2008-04-03 22:33 ZelluX 阅读(1086) | 评论 (0)编辑 收藏

这语言真不错,不像Java那么呆,可惜不开源。
入门看的书是CLR via C#中文版,翻译质量不错,起码到现在还没觉得有必要翻一翻原版(不过为什么中文书都喜欢把“栈”叫成“堆栈”呢)。
前面几章粗略看了下,从第四章类型基础开始重点阅读。
继续漫无目的的学习感兴趣的东西,学习之中经常会惊喜的发现,自己看问题的角度已经不同于之前了。

1. 类的new操作会递归调用该类的所有父类构造器,直到System.Object,后者的构造器只是简单返回,用ILDasm查看MSCorLib.dll可以证实这一点。

2. is和as操作符,is类似于Java中的instanceof,as会先检查类型,如果兼容返回该对象的引用,反之返回null。
Emplooee e = o as Employee;
if (e != null{
    
// blah
}
利用as可以做到只检验一次对象类型,提高程序性能。这本书的很多地方都提到了性能因素。

3. 方法调用和x86上汇编语言调用机制很类似。先是参数入栈,接着返回地址入栈,返回的时候也差不多。不知道x64等寄存器较多的架构上会不会使用寄存器传参呢,呵呵。

4. 作为方法的prologue的一部分,CLR会自动将所有局部变量初始化为null或0。感觉这个自动初始化没什么必要,在第五章可以看到。
SomeVal v1;
SomeVal v1 
= new SomeVal();
这里的SomeVal都是值类型,CLR都会将它们初始化为0。区别在于C#认为前者没有初始化,直接使用这个值会报错;而后者在不赋值的情况下使用这个值。
可能这是CLR和C#之间不统一导致的冗余步骤吧。

5. CLR开始在一个进程中运行时,会给System.Type类型创建一个实例,每个类都会包含指向System.Type类型的指针。

6. CLR提供了执行溢出检查的计算指令,例如add.ovf对应add,mul.ovf对应mul。C#中默认关闭溢出检查。
可以使用checked关键字使用溢出检查。一般情况下,对预计可能发生溢出的代码放到checked块中,对允许溢出的代码(比如计算hash值)放到一个unchecked块中,其他情况,Debug时打开编译器的/checked+开关,Release版本关闭。

7. 所有的值类型都是从System.ValueType继承的。后者重写了Equals方法,比较两个值对象是否完全相等。

8. boxing和unboxing。
boxing:托管堆中分配内存,复制值类型,然后返回对象地址。
unboxing:相当于一个通过指针取值的过程,不过这个指针是已装箱部分中的实际值部分。

9. FCL(Framework Class Library)中包含了支持值类型的泛型容器类,不需要对容器中的元素进行boxing/unboxing处理。
不过这里就有个问题了,值类型的话是放在栈上的,生命周期小于容器的,这个怎么处理呢?
第16章才详细解释泛型,先把这个问题留着吧 =,=

10. 依然是性能问题。有时候编译器会反复对一个值类型boxing,此时手动boxing会提高一些性能。
Int32 v = 5;
// 需三次boxing
Console.WriteLine("{0}, {1}, {2}", v, v, v);

// 只需一次boxing
Object o = v;
Console.WriteLine(
"{0}, {1}, {2}", o, o, o);

接下来书上举了个很搞的例子说明boxing和unboxing的各种情况,其实也很容易理解。

posted @ 2008-04-02 23:33 ZelluX 阅读(1527) | 评论 (14)编辑 收藏

    火车缓缓地开着,混杂的人群。此时的我不属于两边世界中的任何一个,孤立于这种空间和从属感的交界处。理下思路,趁着记忆的新鲜,在手机上敲下这四天的感受,以弥补将来的某天可能发生的对这次旅行的淡忘。

Zijingang Campus: A Fudaner's Perspective

1. Abstract
一次课堂电影(话剧《暗恋桃花源》[5])
旁听两节课,图形学和线性代数。图形学课上回答一次问题 =_=
一场越剧,小百花越剧团的《春琴传》
一场话剧,黑白剧社[1]的《我在天堂等你》[2]
半天图书馆自修,读了半章SICP[4]和一篇paper
半天机房灌水,水木C版版主上任后的第一个操作居然是在浙大完成的
半天在“风雨操场”打球
一晚上在浙大战网打了十盘星际,九胜一负

2. Introduction
    K900到车管所,一站的路程后到达正门。紫金港的正门没有试图制造一种空间隔离感,宽敞的道路上横躺着一块刻有“浙江大学”的石块,构成了形式上的正门。步行百余部后,回头才意识到原来百余步前的所处位置竟是一个入口。
    这个入口给人一种宽广、松驰的感觉,与复旦的正门放置伟人像不同,紫金港的封面很平坦。除了草坪就无其他,可以望到天际。整个紫金港都给我这样的感觉:草坪、树、湖的世界中,点缀着几幢风格各异的建筑。

3. Details
3.1 上课
    其实到浙大吃完饭后做的第一件事就是旁听了一节数媒专业的图形学,上的是三维空间的坐标变换。老师上课进度偏慢,绝大部分学生上课都很认真。感到那么一点点的压力 >,<

3.2 图书馆
    一直觉得图书馆是大学的灵魂组成部分之一。甚至大一的时候觉得有个好的图书馆和一套优秀的借阅制度就足以成为一个好的大学了。也因此新到一个大学后总是特别关注那里的图书馆。
    紫金港图书馆依傍在高耸的行政楼旁,可以把它比成计算中心,行政楼对应于光华主楼,较之后者它们靠得更紧密些。浙大同学说外校同学来看图书馆时,第一反应总是误把行政楼当图书馆。喜欢图书馆的这种低调。
    图书馆的书架分类很笼统,所有的理工类书橱都被贴上了“自然科学”的标签,恐怕找书的时候要很依赖电脑。抽样调查了计算机类书籍,书目较小,重复率较大,甚至会有十几册同本书罢占一层书架的情况。阅读环境很不错,落地窗,明亮。窗外便是那片湖,一如图书馆般地平静。若是把座椅换成摇椅,再加上一杯咖啡,最愉悦的享受莫过于此。
    离开图书馆时还让同学代借了本SICP[4],本想带回上海以此要胁该同学五一来复旦,到时候再还的。无奈多带本书太麻烦,回来之前还是还掉了。

3.3 付费
    住宿楼旁有几家小吃店,其中不少店都是设置了一个单独的付费窗,而这个付费机制里没有任何凭证,或者说点了吃的却不付钱是很容易做到。别的不多说,这样一种店与客之间的信任给人一种亲切感。当然这也和紫金港地理位置较偏远,外人较少有关。

3.4 话剧
    看了黑白剧社[1]的《我在天堂等你》[2]。话剧在一个可容纳百人左右的小书屋里进行。由于一个月前刚看过人艺的《榆树下的欲望》[3],相比之下学生的功底自然略逊一筹,尤其是对老年人的刻划上。不过总体还是很不错的。
    记忆最深的是社员的那份激情,话剧结束后,演员和工作人员挨个自我介绍完毕,然后跑出书屋,站在门口等待出来的观众,齐喊“再见”“谢谢”。下楼走出百余米后,听到后面三声击掌,接着是社员们高喊“谢谢你们”,如此重复几遍,一阵高过一阵。被这种热情所震撼。

3.5 肆
    一位同学的寝室门口贴着一张记录着这个班级同学的奋斗目标之类的墙纸,中间是一个硕大的草体“肆”。奋斗目标都很直接,譬如要被Stanford商学院录取,要进入某某大公司云云。不怎么喜欢这种过于外露的上进心,更欣赏复旦略带散漫的风格。

3.6 还是课
    浙大课比较多。上下午各5节,每节45分钟,中间休息5/15分。同时周末有课也是很常见的现象,为了提高绩点而重修的同学通常周末的课表也很满。个人不喜欢这种课多的生活,喜欢兴趣驱动的学习,不喜欢自己的学习方向太受外力的牵引。

4. The End
    总是有一种声音提醒自己,我不属于这里,注定不属于。太多的不应该出现的巧合,太多的主观的或是客观的借口。我有自己的天地,那里与浙大没有交集,即便我希望会有。

5. Acknowledgements
    感谢浙大那些被我折腾、蹭吃蹭喝的同学。
    感谢版主的m或b。

6. References
[1] 黑白剧社 http://www.qsc.zju.edu.cn/heibai/
[2] 我在天堂等你 http://www.douban.com/subject/1310322/
[3] 榆树下的欲望 Desire Under the Elms, http://www.douban.com/subject/1297393/
[4] Structure and Interpretation of Computer Programs, http://www.douban.com/subject/1451622/
[5] 暗恋桃花源,富含搞笑因素却又错综复杂值得深深体味的一部话剧,推荐一看 http://www.douban.com/subject/1299889/
[6] 春琴传,较传统的日本爱情故事 http://www.douban.com/subject/1949657/

posted @ 2008-03-31 21:18 ZelluX 阅读(558) | 评论 (1)编辑 收藏

其实理解了 Regular Expression -> NFA -> DFA 这个过程,大致的复杂度确定也不难

发信人: styc (styc), 信区: Algorithm
标  题: Re: 请问一下大家正则表达式的时间复杂度
发信站: 水木社区 (Wed Mar 26 20:37:02 2008), 站内

NFA构造O(n),匹配O(nm)
DFA构造O(2^n),最小化O(kn'logn')(N'=O(2^n)),匹配O(m)
n=regex长度,m=串长,k=字母表大小,n'=原始的dfa大小
大概是这样子吧

posted @ 2008-03-27 00:21 ZelluX 阅读(1672) | 评论 (0)编辑 收藏

试试Google Document


posted @ 2008-03-26 17:01 ZelluX 阅读(404) | 评论 (0)编辑 收藏

仅列出标题
共39页: First 上一页 2 3 4 5 6 7 8 9 10 下一页 Last