随笔-281  评论-277  文章-7  trackbacks-0
  2008年7月7日
1、如果用java6的ScriptEngineManager来调用JRuby,并且脚本使用到了Ruby的标准库(比如我用到了YAML库),如果没有正确设置,是会找不到标准库的。通过打印$:变量可以看到文件的加载路径,比如在某台机器上的打印的结果:
   puts $:
   输出:
.
/root/.jruby/lib/ruby/site_ruby/1.8
/root/.jruby/lib/ruby/site_ruby
/root/.jruby/lib/ruby/1.8
/root/.jruby/lib/ruby/1.8/java
lib/ruby/1.8
......略

显然,默认会到当前用户的主目录下寻找.jruby隐藏目录,将此目录作为Ruby的安装目录,因此,可以在~user/.jruby放置一个jruby实现,一劳永逸地解决问题,不然就要自己手工添加完整的路径到$:变量中。

2、nio的临时selector的使用,了解grizzly的都知道,Grizzly框架有一个比较与众不同的地方在于使用临时selector注册channel进行读或者写。这个带来什么好处呢?一个是,通常我们可能将read派发到其他线程中去,如果一次没有读完,那么就得继续注册OP_READ到主selector上;注意,nio在一些平台上有个问题,就是SelectionKey.interestOps方法跟Selector.select方法会有并发冲突,产生奇怪的现象,因此,你会看到大多数的nio框架都会保证SelectionKey.interestOps跟Selector.select的调用在同一个线程;在没有读完继续注册这个场景下,免不了线程间的context switch,如果采用一个临时selector注册并读取,就可以避免这个切换开销。另外,对于write调用,通常你可能这样写:
while (byteBuffer.hasRemaining()) {
  
int len = socketChannel.write(byteBuffer);
  
if (len < 0){
   
throw new EOFException(); 
  }
}


   在负载比较高的时候,write返回0的次数会越来越多,while循环将空耗多次导致CPU占用偏高,这个问题在win32上比较严重,同样可以采用临时selector的解决(Cindy2.x是留在队列,等待下次写)。下例是采用临时Selector进行读的例子:

                Selector readSelector = SelectorFactory.getSelector();
                SelectionKey tmpKey 
= sc.register(readSelector,
                        SelectionKey.OP_READ);
                tmpKey.interestOps(tmpKey.interestOps() 
| SelectionKey.OP_READ);
                
int code = readSelector.select(1000);
                tmpKey.interestOps(tmpKey.interestOps()
                        
& (~SelectionKey.OP_READ));
                
if (code > 0) {
                    
do {
                        n 
= sc.read(in);
                    } 
while (n > 0 && in.hasRemaining());
                    in.flip();
                    decode();
                    in.compact();
                }
                SelectorFactory.returnSelector(readSelector);
    这样的方式,某种意义上可以认为是non-blocking模式下的阻塞读,在网络条件稳定的情况下(比如内网),能带来比较高的效率。

3、spymemcached,是另一个memcached的java client实现,采用nio。最近遇到的问题是它跟原来的MemcachedClient的兼容问题,用它去操作MemcachedClient存储的数据。spymemcached是通过Transcoder来实现序列化,Transcoder的WhalinTranscoder实现类兼容了Greg Whalin的MemcachedClient:
private Transcoder whalinTranscoder = new WhalinTranscoder();


Future
<Object> f = memcachedClient.asyncGet(id, whalinTranscoder);

   各个方法都有重载的版本用以指定Transcoder。
posted @ 2008-07-07 20:41 dennis 阅读(98) | 评论 (0)编辑 收藏
  2008年7月3日
    http://wuhanpin.blogcn.com/index.shtml,来自一线记者关于XXXX事件的blog,谎话重复千遍也就成了真理,但是历史终将还原真实。要看的赶紧看哦,过不了几天恐怕要被河蟹了。
posted @ 2008-07-03 09:16 dennis 阅读(175) | 评论 (0)编辑 收藏
  2008年6月29日
    沸沸扬扬的华南虎案(更想说是闹剧)终于告一段落,在广大网民的火眼金睛下,假老虎终究没有变成真老虎,没有上演指“画”为“虎”的现代成语故事。尽管处理结果有那么点抓小放大的意思,但还是值的纪念的一个日子。
更正:我还是太乐观了,贵州某地发生的事情,让我无法平静,我能做些什么?
posted @ 2008-06-29 16:07 dennis 阅读(129) | 评论 (0)编辑 收藏
  2008年6月23日
    主动关闭的Socket端会进入TIME_WAIT状态,并且持续2MSL时间长度,MSL就是maximum segment lifetime(最大分节生命期),这是一个IP数据包能在互联网上生存的最长时间,超过这个时间将在网络中消失。MSL在RFC 1122上建议是2分钟,而源自berkeley的TCP实现传统上使用30秒,因而,TIME_WAIT状态一般维持在1-4分钟。
    TIME_WAIT状态存在的理由:
1)可靠地实现TCP全双工连接的终止
    在进行关闭连接四路握手协议时,最后的ACK是由主动关闭端发出的,如果这个最终的ACK丢失,服务器将重发最终的FIN,因此客户端必须维护状态信息允许它重发最终的ACK。如果不维持这个状态信息,那么客户端将响应RST分节,服务器将此分节解释成一个错误(在java中会抛出connection reset的SocketException)。因而,要实现TCP全双工连接的正常终止,必须处理终止序列四个分节中任何一个分节的丢失情况,主动关闭的客户端必须维持状态信息进入TIME_WAIT状态。

2)允许老的重复分节在网络中消逝 
    TCP分节可能由于路由器异常而“迷途”,在迷途期间,TCP发送端可能因确认超时而重发这个分节,迷途的分节在路由器修复后也会被送到最终目的地,这个原来的迷途分节就称为lost duplicate。在关闭一个TCP连接后,马上又重新建立起一个相同的IP地址和端口之间的TCP连接,后一个连接被称为前一个连接的化身(incarnation),那么有可能出现这种情况,前一个连接的迷途重复分组在前一个连接终止后出现,从而被无解成从属于新的化身。为了避免这个情况,TCP不允许处于TIME_WAIT状态的连接启动一个新的化身,因为TIME_WAIT状态持续2MSL,就可以保证当成功建立一个TCP连接的时候,来自连接先前化身的重复分组已经在网络中消逝。

新的SCTP协议通过在消息头部添加验证标志避免了TIME_WAIT状态。
posted @ 2008-06-23 01:25 dennis 阅读(189) | 评论 (0)编辑 收藏
  2008年6月22日
    欧洲杯开赛至今,由于要上班,担心起不了床,完整的比赛没看过几场,错过好多场精彩对决了,今天晚上熬夜看俄罗斯VS.荷兰,真值了,阿尔沙文成了俺的新偶像,过人如草芥,太牛X了。这厮在FM2008里就很猛了,我的朴茨茅斯档第一个买的就是他,第一年就排上了联赛第三,让他打前腰,助攻第一,进球全队第三,性价比超值。


posted @ 2008-06-22 05:43 dennis 阅读(174) | 评论 (0)编辑 收藏
  2008年6月21日
    加班在国内的公司好像是司空见惯的事情,更司空见惯的是加班不给加班费。从业三年,加班次数也不少,不过最长的一次是连续加了一个月的班,天天10点多才回家,比起某些同学深更半夜还在加班的差了些。在目前的公司,除了刚开始偶尔加班外,现在我基本就是下班就走人了,还没有因为我负责的模块延期导致的项目的延期,相反,自信工作的效率还是比较高的,自然上班时间能搞定的事情,何必拖到下班后?
    不排除有些人喜欢安静的环境,下班后,人少了,一个人敲代码感觉更好,效率更高。这其实颠倒了问题的本质,本质是公司没有为员工创造一个舒适的工作环境,“家具警察”们是绝不乐意给你安排一个私人小空间的。问题是,代码不是生活的全部,如果天天这样晚上在公司加班,可以想见这人的生活该如何枯燥,而生活枯燥的人很容易失去想象力和直觉,并且心理上难免会有点毛病。公司不应该鼓励加班,公司应该鼓励的是大家在上班期间高效地完成工作,然后尽快回家去“生活”。其实吧,如果我们上班少看点新闻,少开点小差,这个效率绝对是不低的。
    听闻有领导对我们部门不满,说我们部门总是下班后人都走光了:)这样的观点真是奇怪,难道加班就能显示这个部门很努力、很负责?况且,我看到很多加班的同学更多是在玩游戏或者干自己的事情,公司领导们难道看不到这一点?或者他们只要看见有人在那,心里就比较舒服点。这其实很奇怪的,我认为经常加班的部门绝对是有问题的,而且很大程度上是项目管理不当引起的。

posted @ 2008-06-21 12:32 dennis 阅读(233) | 评论 (9)编辑 收藏
  2008年6月18日
    SocketChannel和ServerSocketChannel,两者的父类是SelectableChannel,它在jdk中的文档有这么段话:

    Once registered with a selector, a channel remains registered until it is deregistered.This involves deallocating whatever resources were allocated to the channel by the selector.
    A channel cannot be deregistered directly; instead, the key representing its registration must be cancelled. Cancelling a key requests that the channel be deregistered during the selector's next selection operation.

    也就是说关闭一个已经注册的SelectableChannel需要两个步骤:

1)取消注册的key,这个可以通过SelectionKey.cancel方法,也可以通过SelectableChannel.close方法,或者中断阻塞在该channel上的IO操作的线程来做到。

2)后续的Selector.selectXXX方法的调用才真正地关闭本地Socket。

    因而,如果,如果在取消SelectionKey后没有调用到selector的select方法(因为Client一般在取消key后, 我们都会终止调用select的循环,当然,server关闭一个注册的channel我们是不会终止select循环的),那么本地socket将进入CLOSE-WAIT状态(等待本地Socket关闭)。简单的解决办法是在 SelectableChannel.close方法之后调用Selector.selectNow方法,类似:

   Selector sel;
   SocketChannel sch;
   // …
   sch.close();
   sel.selectNow();


    Nio编程有很多这样细节性的东西需要注意,通常情况下还是利用成熟的框架为妙。

posted @ 2008-06-18 01:50 dennis 阅读(1221) | 评论 (1)编辑 收藏
  JavaOne2008上有个session《Upcoming Java Programming Language Features》,讲了即将到来的jdk7可能引入的新的语言特性,比较开眼界的是jsr308对Annotation的扩展使用,更多地作为断言或者说checker使用以便减少bug。在ppt前面,我觉的更有意思的是对java语言演化的讲述,做个笔记。

1、应用VS.语言

应用是特性越多越好,应用是rich的;而语言是pure的,更少的、普通的特性更好。

2、添加一个java语言特性的三个前提:尊重过去、着眼未来以及顾及模型。

无论是增加、减少或者改变一个feature都可能broken已经存在的代码,一个新增加的feature必须兼容已经存在的代码,兼容是个沉重的包袱,就java语言而言,我相当认同尊重过去这一点,哪怕加入闭包这样的特性也不应当以损坏兼容性为代价,更好的选择是将这些特性让jvm上的新语言去实现(比如JRuby、Scala),java语言作为成熟的工业语言本身不应当做太大的改变。而着眼未来,也就是说新的语言特性应该为未来的语法扩展留有空间,它的语法/语义不应当跟现存的或者潜在的特性相冲突,以便可以持续地演化。再谈顾及当前的模型,一门语言代表着一种计算模型,比如simulaOO模型(classes)Erlang就是inter-process communication的模型(actor)。Java语言也有一个简单的模型:首先它是“高层”语言,是一门通用、并发、基于类的OO语言,其次,它跟APIJVM有良好的结合。Java语言模型有四个原则:

a)鼓励high-level实践,通过抽象来隐藏偶然复杂度。简而言之:do the right thing

b)追求清晰,程序被读的时候远远多于写。简而言之:do the thing right.

c)青睐静态类型,静态类型能增进对代码的信心,静态类型能证明bug在编译时的不存在,而测试和动态类型能证明bug的存在。我的观点是,大多数难以寻找和解决的bug都是runtime的,静态类型在此方面能给出的帮助有限,充分并且适宜的测试更加能增强你对应用的信心。

d)语言比之API的更广泛。one language,many apiAPI来去匆匆,而语言却是forever,因而将语言和API分离是明智的,一些特性可以做为库来实现,jdk5并发库的引入就很好,jdk7在并发方面同样将引入fork/join模型。

java语言的演化也当遵循这四个原则。再看看传说中的闭包语言,当它跟泛型结合的时候写出来的东西还谈得上清晰吗?闭包的实现能否解决兼容性问题也是个疑问。就四个提案,C3S需要引入method关键字(类似lambda),FCM的#号看起来比较怪异,在我看来,CICE和BGGA更符合胃口,CICE对java语言的变动应该最小,学习曲线也比较平缓,BGGA的=>符号更有函数式语言的味道。闭包的引入,某种程度上能减少敲击键盘的次数并实现一些高阶功能,特别是在聚合操作(如filter、map等)和单抽象方法类(如Runnable,Callable)的使用上,但是在现代IDE的自动化帮助下,这个带来的价值是值的怀疑的。




posted @ 2008-06-18 00:20 dennis 阅读(1450) | 评论 (0)编辑 收藏
  2008年6月14日
    今天同事遇到的问题,用JRuby调用一个java方法,该方法使用了jdk1.5的可变参数。我一开始以为只要简单地将可变参数表示为数组即可,例如下面的两个java类:
public class Echo{
    
public void echo(String name){
       System.out.println(name);
    }
}
public class Test{
    
public void hello(String name,Echoargs){
        System.out.println(
"hello,"+name);
        
for(Echo e:args){
            e.echo(name);
        }
    }
}
   我想在jruby中调用Test的hello方法,该方法有个可变参数args。所谓可变参数经过编译后其实也就是数组,这个可以通过观察字节码知道,那么如果用数组来调用可以不?
require 'java'
require 
'test.jar'
include_class 
'Test'
include_class 
'Echo'
t.hello(
"dennis")  #报错,参数不匹配
t.hello("dennis",[])  #报错,类型不匹配
   很遗憾,这样调用是错误的,原因如上面的注释。具体到类型不匹配,本质的原因是JRuby中的数组与java中对数组的字节码表示是不一致的,JRuby中的数组是用org.jruby.RubyArray类来表示,而hello方法需要的数组却是是[LEcho。解决的办法就是将JRuby的数组转成java需要的类型,通过to_java方法,因而下面的调用才是正确的,尽管显的麻烦:
require 'java'
require 
'test.jar'
include_class 
'Test'
include_class 
'Echo'
t
=Test.new
t.hello(
"dennis",[].to_java("Echo"))
e1
=Echo.new
t.hello(
"dennis",[e1].to_java("Echo"))
e2
=Echo.new
t.hello(
"dennis",[e1,e2].to_java("Echo"))


posted @ 2008-06-14 22:39 dennis 阅读(1055) | 评论 (1)编辑 收藏
  2008年6月13日

     头发乃人之元,很多人看人,第一眼看的就是你的头发,当然看MM的部位可能不一样。我的头发从来都是像野草一样,从来没放心思在上面,都是理一次头发大半年不管他,长的跟杂草似的难受,然后回家找小区内的师傅理发——或者说剃头,而且发型从来都是板寸头,短短的,免的大半年不回家还得在外面理发。因而,我的理发时间跟我的回家时间一样。

小时候,那时候住在老家,没有专门的理发店,也可能是离我家的小村庄很远。有个走村串户的剃头匠,大概几个月能在村里见他一次,带着一身行头,谁家有人要剃头,就请他过去。记的那时是没用电的理发工具,一把类似夹子的东西,老师傅手工在各式各样的脑袋上推来推去,然后搞些肥皂水就着自家的井水冲洗。后来很久没再见到这位老师傅,而隔壁村开了家理发店,大人们就带着我们走路或者骑着自行车去隔壁村剃头了,记的那位师傅还是我们大队的干部,隔壁是猪肉店,至于剃头的细节却是记不清了。再后来隔壁村又开了一家理发店,是个小青年开的,印象特别深的一次是我奶奶带我过去理发,小青年说如果我帮他打一桶井水,钱可以减半。我帮他打了桶井水,然后真给我减半了,就着自己打的井水冲洗我的不规则的大脑袋。后来,跟父母搬到了县城,去外地读书,就再也没在老家理发过了,好几年之后路过小青年开的那家店,装修了,蓝色的玻璃后面,小青年变成了师傅,指导着自己的徒弟在理发,我想,大概他也记不得当年那个给他打水的小屁孩了。

进城了,我理发就固定在小区的周师傅这了。上大学,基本是五一、十一和春节回家的时候剃一次,哪怕再长,还是不愿意在福州理发,分不清是习惯还是莫名其妙的坚持了。其实挺不好意思的,每次都留那么长的头发,周师傅也还是固定收我5块钱,不过今年涨价了,7块。下午剃头的时候,周师傅的女儿找他要100来块钱,旁边的人问周师傅她拿去做啥呢?周师傅说去染发,语气有点黯然。父亲理的老式发型,女儿是不会喜欢的。我的头发就这样随着我离家的远近轮回着,现在在广州,回家还是容易的,以后去哪还是不知道的事情,希望还能半年回家一次理发。

posted @ 2008-06-13 21:54 dennis 阅读(216) | 评论 (4)编辑 收藏
仅列出标题  下一页