(FYI: The following entry is going to be much more technical than most of what I post. Anyone who doesn't care about code or data serialization can pretty much hit "next" right now.)

A few days ago, Google open sourced one of its key data serialization formats, protocol buffers. There's already been some chat on how they're similar to or different than other wire formats, but I thought it would be useful to post some useful tips I've come across over the years about how to make them do useful things.

Don't expect any deep insights into computer science here, just a few notes about working with these libraries.

When to use protocol buffers
Basically, use them when you have data you may want to serialize. Don't use them for structs in inner loops, since there's a performance overhead of checking the has_* bits during each access, but if you aren't writing anything that needs to be that tightly optimized, you can just go ahead. PB's are excellent things to stick in tables, but you should also stick some note somewhere of which PB is actually being used, since their wire format doesn't have that data. A lot of the time that's obvious from context, so you needn't worry.

If you have data that needs to be compressed, use common sense. A posting list from an inverted index should not be expressed as a repeated message inside a protocol buffer; it should be written with a good compression function so you can scan it quickly. But it does make sense to have a protocol buffer whose fields describe the compression type, and which has one string field that holds the compressed payload; that makes adding new compression types and various other list-processing tasks a hell of a lot easier.

Things to remember about the wire format
  1. The basic format of PB's is a sequence of entries, one for each tag that shows up. There's a header, which consists of a combination of the tag number which is being encoded and the wire format as which it's being written, written out as a varint, and that's followed immediately by the payload. So if you have a 'required int32 foo = 1', the header will be a combination of 1 (the tag number) and the enum NUMERIC indicating that the wire format is a varint32.
  2. As an interesting side effect, this means that for tag numbers 1 through 15, the header is always a single byte. So if you care about space usage of your proto on the wire, and one field is going to be very common and/or repeated a lot, make sure to give it a low tag number. Give fields that are going to be used for debugging only really high tag numbers.
  3. If a PB includes another PB, the wire format for an included message is the same as that for a string -- it's just that the string in question is another PB, serialized. So you can nest things, pass serialized PB's around, and play various games in the obvious fashion.
  4. Another interesting thing is that the order in which PB tags are serialized isn't specified, so you can play various games by smashing two serialized PB's together. For example, if you need to generate N serialized PB's of the same type which are identical except for one field, you can set up the PB without that field and serialize it to a string; then clear it, and N times (fill just that field, serialize it, append that to the fixed string). Much faster than doing a full serialization over and over.
  5. You can also use this to put together protocol buffers based on other kinds of user input, like CGI arguments; read in a bunch of key/value pairs from wherever, use the PB's introspection methods to get a tag number from the key and the protocol definition, then use the low-level serialization methods to write out (tag, wire format, value) to a string. Deserialize when you're done. It's a little ugly, but it's fairly efficient and typically only needs to be done once or twice. Of course, if you're accepting CGI arguments from the outside world, sanitizing them is your own lookout.
  6. One thing I've come to truly appreciate is how useful the ASCII serializations can be. Common tricks: Use the short ASCII format (one-line) as a way to interpret something users type. Command-line flags are one good application, as are config files.
    Another neat trick is if one is writing complicated types like query trees that require a special parser. (You can write tree structures entirely in PB's. The resulting ASCII format is not very easy to read. Write your own. I'm personally fond of s-expressions) You'll often want to be able to add elaborate annotations to each node of a tree; use a protocol buffer to represent that, and (de)serialize them with the short ASCII representation. It ends up looking something like (AND [onetag:3 anothertag:"foo"]wombat [onetag:4]soufflé). What's nice is that you can then add a new field to the protocol message, and it's instantly added to both the serialized and internal (tree) representations, without having to muck about with the s-expression parser.
    Another version of this trick: At one point I had to write a rather complex data serializer and compressor. Its wire format was a protocol buffer, the first bit of which was data about how the main field (a string) was compressed; the functions that generated it took this protocol buffer, minus the payload field, and then serialized data into it. So for unittests, one could simply have a test function that took a string argument which was the ASCII representation of the non-payload part of the PB; the function then made up some data, serialized and deserialized it, etc. But this meant that a lot of the body of the test looked like TestCompression("format:UNCOMPRESSED bytesperentry:8"); and other similarly legible stuff. Honestly, these minor legibility improvements make life a lot simpler than one would guess.


Important useful thing about protos which may or may not be initially obvious
If the protocol deserializer comes across a tag number which isn't in its copy of the protocol definition, it will just keep it as uninterpreted data and pass it along when it reserializes the proto. So if you have three servers, and A sends a message to B which processes it and then sends it on to C, and you want to add a new field which A uses to communicate something to C, you don't need to update the B server; it will just pass the updated protocol message along to C. I can't even begin to tell you how much more pleasant this can make your life.

One more thing
The constructors and destructors of protocol messages are fairly expensive. Reuse them whenever possible, even at the expense of having a slightly broader variable scoping than you would like.

http://zunger.livejournal.com/164024.html

 

posted @ 2009-12-30 11:54 tmrp 阅读(207) 评论(0) 编辑
锁(lock)作为用于保护临界区(critical section)的一种机制,被广泛应用在多线程程序中。无论是 Java 语言中的 synchronized 关键字,还是 java.util.concurrent 包中的 ReentrantLock,都是多线程应用开发人员手中强有力的工具。但是强大的工具通常是把双刃剑,过多或不正确的使用锁,会导致多线程应用的性能下降。这种问题在多核平台成为主流的今天越发明显。

        竞争锁是造成多线程应用程序性能瓶颈的主要原因

        区分竞争锁和非竞争锁对性能的影响非常重要。如果一个锁自始至终只被一个线程使用,那么 JVM 有能力优化它带来的绝大部分损耗。如果一个锁被多个线程使用过,但是在任意时刻,都只有一个线程尝试获取锁,那么它的开销要大一些。我们将以上两种锁称为非竞争锁。而对性能影响最严重的情况出现在多个线程同时尝试获取锁时。这种情况是 JVM 无法优化的,而且通常会发生从用户态到内核态的切换。现代 JVM 已对非竞争锁做了很多优化,使它几乎不会对性能造成影响。常见的优化有以下几种。

        * 如果一个锁对象只能由当前线程访问,那么其他线程无法获得该锁并发生同步 , 因此 JVM 可以去除对这个锁的请求。
        * 逸出分析 (escape analysis) 可以识别本地对象的引用是否在堆中被暴露。如果没有,就可以将本地对象的引用变为线程本地的 (thread local) 。
        * 编译器还可以进行锁的粗化 (lock coarsening) 。把邻近的 synchronized 块用相同的锁合并起来,以减少不必要的锁的获取和释放。

        因此,不要过分担心非竞争锁带来的开销,要关注那些真正发生了锁竞争的临界区中性能的优化。

        降低锁竞争的方法

        很多开发人员因为担心同步带来的性能损失,而尽量减少锁的使用,甚至对某些看似发生错误概率极低的临界区不使用锁保护。这样做往往不会带来性能提高,还会引入难以调试的错误。因为这些错误通常发生的概率极低,而且难以重现。

        因此,在保证程序正确性的前提下,解决同步带来的性能损失的第一步不是去除锁,而是降低锁的竞争。通常,有以下三类方法可以降低锁的竞争:减少持有锁的时间,降低请求锁的频率,或者用其他协调机制取代独占锁。这三类方法中包含许多最佳实践,在下文中将一一介绍。

        避免在临界区中进行耗时计算

        通常使代码变成线程安全的技术是给整个函数加上一把“大锁”。例如在 Java 中,将整个方法声明为 synchronized 。但是,我们需要保护的仅仅是对象的共享状态,而不是代码。

        过长时间的持有锁会限制应用程序的可扩展性。 Brian Goetz 在《 Java Concurrency in Practice 》一书中提到,如果一个操作持有锁的时间超过 2 毫秒,并且每一个操作都需要这个锁,那么无论有多少个空闲处理器,应用程序的吞吐量都不会超过每秒 500 个操作。如果能够减少持有这个锁的时间到 1 毫秒,就能将这个与锁相关的吞吐量提高到每秒 1000 个操作。事实上,这里保守地估计了过长时间持有锁的开销,因为它并没有计算锁的竞争带来的开销。例如,因为获取锁失败带来的忙等和线程切换,都会浪费 CPU 时间。减小锁竞争发生可能性的最有效方式是尽可能缩短持有锁的时间。这可以通过把不需要用锁保护的代码移出同步块来实现, 尤其是那些花费“昂贵”的操作,以及那些潜在的阻塞操作,比如 I/O 操作。

        在例 1 中,我们使用 JLM(Java Lock Monitor) 查看 Java 中锁使用的情况。 foo1 使用 synchronized 保护整个函数,foo2 仅保护变量 maph 。 AVER_HTM 显示了每个锁的持有时间。可以看到将无关语句移出同步块后,锁的持有时间降低了,并且程序执行时间也缩短了。

posted @ 2009-07-20 20:49 tmrp 阅读(55) 评论(0) 编辑

今天学了一下午的正则表达式(马士兵的那个视频教程),这RegularExpressions也算是一门小语言了,唯一让我不能理解的就是API里非捕获组中的那些用法,经过在论坛的查找学习,呵呵 ,现在终于理解了,下面与大家分享下。

 

捕获组(capturing group)是把多个字符当作一个单元对待的一种方式。通过把字符括在括号内创建捕获组。例如,正则表达式(dog)创建包含字母“d”、“o”和“g”的一个组。输入字符串和捕获组匹配的那一部分将被保存在内存中,以便以后通过反向引用再次使用。

而非捕获组就是输入字符串和捕获组匹配的那一部分将不被保存在内存中。这有什么用呢?当然是能够节省内存了,下面具体说下非捕获组里的那8个Special constructs(下面的内容大部分是我摘抄论坛上一个叫“火龙果”兄弟的回贴,然后再加上些我自己的理解):

 

以 (? 开头的都是非捕获组,都是不进行捕获的。

(?:XXX) 这个比较常用,在不需要捕获时可以替换 (XXX),比如:


匹配 June 和 July 可以写成:
Ju(ne|ly)

也可以写成
Ju(?:ne|ly)

前者会把 ( ) 内的在匹配后保留在内存中,而后者不会。

以 (? 开头,) 结尾的都称为非捕获组,在匹配完成后在内存中不保留匹配到的字符。

 

(1)(?:X)

    X 作为非捕获组
与捕获组 ( ) 的意思一样也是将其作为一组进行处理,与捕获组的区别在于不捕获匹配的文本,
仅仅作为分组。
比如:要匹配 123123 这个,就可以写为 (123)\1 使用反向引用,这时只能用捕获组,在匹配
123 后会保留在内存中,便于反向引用,而 (?:123) 在匹配完后则不会保留,区别仅在于此。

 

(2)(?idmsux-idmsux)  Nothing,但是将匹配标志i d m s u x on - off
用于标志匹配,比如:表达式 (?i)abc(?-i)def 这时,(?i) 打开不区分大小写开关,abc 匹配
不区分大小地进行匹配,(?-i) 关闭标志,恢复不区分大小写,这时的 def 只能匹配 def

(?idmsux-idmsux:X)  X,作为带有给定标志 i d m s u x on - off
与上面的类似,上面的表达式,可以改写成为:(?i:abc)def,或者 (?i)abc(?-i:def)

 

(3)(?=X) X,通过零宽度的正 lookahead
    (?!X) X,通过零宽度的负 lookahead
(?=X) 表示当前位置(即字符的缝隙)后面允许出现的字符,比如:表示式 a(?=b),在字符串为
ab 时,可能匹配 a,后面的 (?=b) 表示,a 后面的缝隙,可以看作是零宽度。
(?!X) 表示当前位置后面不允许出现的字符

 

(4)(? <=X) X,通过零宽度的正 lookbehind
    (? <!X) X,通过零宽度的负 lookbehind
这两个与上面两个类似,上面两个是向后看,这个是向前看
 (5)(?>X) X,作为独立的非捕获组
匹配成功不进行回溯,这个比较复杂,与侵占量词“+”可以通用,比如:\d++ 可以写为 (?>\d+)。

 

这里的侵占量词就是Possessive quantifiers,在API中的描述很好理解。

在这里我补充下 Reluctant quantifiers  Possessive quantifiers  Greedy quantifiers的区别,以便大家能更好的理解,看下面的这个例子:

  Pattern p = Pattern.compile(".{3,10}+[0-9]");
  String s = "aaaa5bbbb6";
  Matcher m = p.matcher(s);
  if(m.find())
   p(m.start() + "-" + m.end());
  else
   p("not match!");

注意正则表达式中的那个加号,他就代表Possessive quantifiers ,这里的输出结果是not match,而如果我们将“+”改为“?”,即".{3,10}?[0-9]",那么输出的是

0-5,这就是Reluctant quantifiers  ,而我们最常用的Greedy quantifiers,

".{3,10}[0-9]",输出的是0-10.

 

为什么会这样呢? Possessive 英文意思占有的,在上面的程序中查找匹配的字符串时,注意这里是{3,10},所以直接取s的10个字符,即使后面还要有一个数字,他也不“吐出”一个字符,让匹配成功,所以就输出not match,而Reluctant quantifiers呢,他“勉强”的取字符,找到一个字符最少的匹配串,而 Greedy quantifiers它能够回溯 。

 

 

一个说明独立非捕获组的例子:
将一些多位的小数截短到三位小数:

\d+\.\d\d[1-9]?\d+

在这种条件下 6.625 能进行匹配,这样做没有必要,因为它本身就是三位小数。最后一个“5”本来是给 [1-9] 匹配的,但是后面还有一个 \d+ 所以,[1-9] 由于是“?”可以不匹配所以只能放弃当前的匹配,将这个“5”送给 \d+ 去匹配,如果改为:

\d+\.\d\d[1-9]?+\d+

的侵占形式,在“5”匹配到 [1-9] 时,由于是侵占式的,所以不会进行回溯,后面的 \d+ 就匹配不到任东西了,所以导致 6.625 匹配失败。

这种情况,在替换时就有效了,比如把数字截短到小数点后三位,如果正好是三位小数的,就可以不用替换了,可以提高效率,侵占量词基本上就是用来提高匹配效率的。

把 \d+\.\d\d[1-9]?+\d+ 改为 \d+\.\d\d(?>[1-9]?)\d+ 这样是一样的。

文章出处:http://www.diybl.com/course/3_program/java/javajs/20081217/154146.html

posted @ 2009-07-20 14:32 tmrp 阅读(474) 评论(0) 编辑

作为Java程序员来说,最痛苦的事情莫过于可以选择的范围太广,可以读的书太多,往往容易无所适从。我想就我自己读过的技术书籍中挑选出来一些,按照学习的先后顺序,推荐给大家,特别是那些想不断提高自己技术水平的Java程序员们。

一、Java编程入门类

对于没有Java编程经验的程序员要入门,随便读什么入门书籍都一样,这个阶段需要你快速的掌握Java基础语法和基本用法,宗旨就是“囫囵吞枣不求甚解”,先对Java熟悉起来再说。用很短的时间快速过一遍Java语法,连懵带猜多写写代码,要“知其然”。

1、《Java编程思想》

在有了一定的Java编程经验之后,你需要“知其所以然”了。这个时候《Java编程思想》是一本让你知其所以然的好书,它对于基本的面向对象知识有比较清楚的交待,对Java基本语法,基本类库有比较清楚的讲解,可以帮你打一个良好的Java编程基础。这本书的缺点是实在太厚,也比较罗嗦,不适合现代人快节奏学习,因此看这本书要懂得取舍,不是每章每节都值得一看的,挑重点的深入看就可以了。

2、《Agile Java》中文版

这本书是出版社送给我的,我一拿到就束之高阁,放在书柜一页都没有翻过,但是前两天整理书柜的时候,拿出来一翻,竟然发现这绝对是一本好书!这本书一大特点是以单元测试和TDD来贯穿全书的,在教你Java各种重要的基础知识的过程中,潜移默化的影响你的编程思维走向敏捷,走向TDD。另外这本书成书很新,以JDK5.0的语法为基础讲解,要学习JDK5.0的新语法也不错。还有这本书对于内容取舍也非常得当,Java语言毕竟类库庞大,可以讲的内容太多,这本书选择的内容以及内容的多寡都很得当,可以让你以最少的时间掌握Java最重要的知识,顺便培养出来优秀的编程思路,真是一本不可多得的好书。

虽然作者自己把这本书定位在入门级别,但我不确定这本书用来入门是不是稍微深了点,我自己也准备有空的时候翻翻这本书,学习学习。


二、Java编程进阶类

打下一个良好的Java基础,还需要更多的实践经验积累,我想没有什么捷径。有两本书值得你在编程生涯的这个阶段阅读,培养良好的编程习惯,提高你的代码质量。

1、《重构 改善既有代码的设计》

这本书名气很大,不用多介绍,可以在闲暇的时候多翻翻,多和自己的实践相互印证。这本书对你产生影响是潜移默化的。

2、《测试驱动开发 by Example》
本书最大特点是很薄,看起来没有什么负担。你可以找一个周末的下午,一边看,一边照做,一个下午就把书看完,这本书的所有例子跑完了。这本书的作用是通过实战让你培养TDD的思路。

三、Java架构师之路

到这个阶段,你应该已经非常娴熟的运用Java编程,而且有了一个良好的编程思路和习惯了,但是你可能还缺乏对应用软件整体架构的把握,现在就是你迈向架构师的第一步。

1、《Expert One-on-One J2EE Design and Development》

这本书是Rod Johnson的成名著作,非常经典,从这本书中的代码诞生了springframework。但是好像这本书没有中译本。

2、《Expert One-on-One J2EE Development without EJB》

这本书由gigix组织翻译,多位业界专家参与,虽然署名译者是JavaEye,其实JavaEye出力不多,实在是忝居译者之名。

以上两本书都是Rod Johnson的经典名著,Java架构师的必读书籍。在我所推荐的这些书籍当中,是我看过的最仔细,最认真的书,我当时读这本书几乎是废寝忘食的一气读完的,有小时候挑灯夜读金庸武侠小说的劲头,书中所讲内容和自己的经验知识一一印证,又被无比精辟的总结出来,读完这本书以后,我有种被打通经脉,功力爆增的感觉。

但是后来我看过一些其他人的评价,似乎阅读体验并没有我那么high,也许是因为每个人的知识积累和经验不同导致的。我那个时候刚好是经验知识积累已经足够丰富,但是还没有系统的整理成型,让这本书一梳理,立刻形成完整的知识体系了。

3、《企业应用架构模式》

Martin的又一本名著,但这本书我只是泛泛的看了一遍,并没有仔细看。这本书似乎更适合做框架的人去看,例如如果你打算自己写一个ORM的话,这本书是一定要看的。但是做应用的人,不看貌似也无所谓,但是如果有空,我还是推荐认真看看,会让你知道框架为什么要这样设计,这样你的层次可以晋升到框架设计者的角度去思考问题。Martin的书我向来都是推崇,但是从来都没有像Rod Johnson的书那样非常认真去看。

4、《敏捷软件开发原则、模式与实践》
Uncle Bob的名著,敏捷的经典名著,这本书比较特别,与其说是讲软件开发过程的书,不如说讲软件架构的书,本书用了很大篇幅讲各种面向对象软件开发的各种模式,个人以为看了这本书,就不必看GoF的《设计模式》了。


四、软件开发过程

了解软件开发过程不单纯是提高程序员个人的良好编程习惯,也是增强团队协作的基础。

1、《UML精粹》

UML其实和软件开发过程没有什么必然联系,却是软件团队协作沟通,撰写软件文档需要的工具。但是UML真正实用的图不多,看看这本书已经足够了,完全没有必要去啃《UML用户指南》之类的东西。要提醒大家的是,这本书的中译本翻译的非常之烂,建议有条件的看英文原版。

2、《解析极限编程 拥抱变化》XP

这是Kent Beck名著的第二版,中英文对照。没什么好说的,必读书籍。

3、《统一软件开发过程》UP

其实UP和敏捷并不一定冲突,UP也非常强调迭代,测试,但是UP强调的文档和过程驱动却是敏捷所不取的。不管怎么说,UP值得你去读,毕竟在中国真正接受敏捷的企业很少,你还是需要用UP来武装一下自己的,哪怕是披着UP的XP。

4、《敏捷建模》AM

Scott Ambler的名著,这本书非常的progmatic,告诉你怎么既敏捷又UP,把敏捷和UP统一起来了,又提出了很多progmatic的建议和做法。你可以把《解析极限编程拥抱变化》、《统一软件开发过程》和《敏捷建模》这三本书放在一起读,看XP和UP的不同点,再看AM是怎么统一XP和UP的,把这三种理论融为一炉,形成自己的理论体系,那么你也可以去写书了。


五、软件项目管理

如果你突然被领导提拔为项目经理,而你完全没有项目管理经验,你肯定会心里没底;如果你觉得自己管理项目不善,很想改善你的项目管理能力,那么去考PMP肯定是远水不解近渴的。

1、《快速软件开发》

这也是一本名著。可以这样说,有本书在手,你就有了一个项目管理的高级参谋给你出谋划策,再也不必担心自己不能胜任的问题了。这本书不是讲管理的理论的,在实际的项目管理中,讲这些理论是不解决问题的,这本书有点类似于“软件项目点子大全”之类的东西,列举了种种软件项目当中面临的各种问题,以及应该如何解决问题的点子,你只需要稍加变通,找方抓药就行了。


六、总结

在这份推荐阅读书籍的名单中,我没有列举流行的软件框架类学习书籍,例如Struts,Hibernate,Spring之类,也没有列举AJAX方面的书籍。是因为这类书籍容易过时,而上述的大半书籍的生命周期都足够长,值得你去购买和收藏。

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/gangqinjiawang/archive/2009/07/14/4346027.aspx

posted @ 2009-07-19 22:28 tmrp 阅读(44) 评论(0) 编辑

转载自....咕~~(╯﹏╰)b, 请原作者在下面留真名, 我好给你写上来.

前言

  Java的路径问题,非常难搞。最近的工作涉及到创建和读取文件的工作,这里我就给大家彻底得解决Java路径问题。

  我编写了一个方法,比ClassLoader.getResource(String 相对路径)方法的能力更强。它可以接受"../"这样的参数,答应我们用相对路径来定位classpath外面的资源。这样,我们就可以使用相对于classpath的路径,定位所有位置的资源!

  Java路径

  Java中使用的路径,分为两种:绝对路径和相对路径。具体而言,又分为四种:

  一、URI形式的绝对资源路径

  如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/aaa.b

  URL是URI的特例。URL的前缀/协议,必须是Java熟悉的。URL可以打开资源,而URI则不行。

  URL和URI对象可以互相转换,使用各自的toURI(),toURL()方法即可!

  二、本地系统的绝对路径

  D:/java/eclipse32/workspace/jbpmtest3/bin/aaa.b

  Java.io包中的类,需要使用这种形式的参数。

  但是,它们一般也提供了URI类型的参数,而URI类型的参数,接受的是URI样式的String。因此,通过URI转换,还是可以把URI样式的绝对路径用在java.io包中的类中。

  三、相对于classpath的相对路径

  如:相对于

  file:/D:/java/eclipse32/workspace/jbpmtest3/bin/这个路径的相对路径。其中,bin是本项目的classpath。所有的Java源文件编译后的.class文件复制到这个目录中。

  四、相对于当前用户目录的相对路径

  就是相对于System.getProperty("user.dir")返回的路径。

  对于一般项目,这是项目的根路径。对于JavaEE服务器,这可能是服务器的某个路径。这个并没有统一的规范!

  所以,绝对不要使用"相对于当前用户目录的相对路径"。然而:

  默认情况下,java.io 包中的类总是根据当前用户目录来分析相对路径名。此目录由系统属性 user.dir 指定,通常是 Java 虚拟机的调用目录。

  这就是说,在使用java.io包中的类时,最好不要使用相对路径。否则,虽然在J2SE应用程序中可能还算正常,但是到了J2EE程序中,一定会出问题!而且这个路径,在不同的服务器中都是不同的!

  相对路径最佳实践

  推荐使用相对于当前classpath的相对路径

  因此,我们在使用相对路径时,应当使用相对于当前classpath的相对路径。

  ClassLoader类的getResource(String name),getResourceAsStream(String name)等方法,使用相对于当前项目的classpath的相对路径来查找资源。

  读取属性文件常用到的ResourceBundle类的getBundle(String path)也是如此。

  通过查看ClassLoader类及其相关类的源代码,我发现,它实际上还是使用了URI形式的绝对路径。通过得到当前classpath的URI形式的绝对路径,构建了相对路径的URI形式的绝对路径。(这个实际上是猜想,因为JDK内部调用了SUN的源代码,而这些代码不属于JDK,不是开源的。) 相对路径本质上还是绝对路径

  因此,归根结底,Java本质上只能使用绝对路径来寻找资源。所有的相对路径寻找资源的方法,都不过是一些便利方法。不过是API在底层帮助我们构建了绝对路径,从而找到资源的!

  得到classpath和当前类的绝对路径的一些方法

  下面是一些得到classpath和当前类的绝对路径的一些方法。你可能需要使用其中的一些方法来得到你需要的资源的绝对路径。

  1.FileTest.class.getResource("")

  得到的是当前类FileTest.class文件的URI目录。不包括自己!

  如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/com/test/

  2.FileTest.class.getResource("/")

  得到的是当前的classpath的绝对URI路径。

  如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/

  3.Thread.currentThread().getContextClassLoader().getResource("")

  得到的也是当前ClassPath的绝对URI路径。

  如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/

  4.FileTest.class.getClassLoader().getResource("")

  得到的也是当前ClassPath的绝对URI路径。

  如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/

  5.ClassLoader.getSystemResource("")

  得到的也是当前ClassPath的绝对URI路径。

  如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/

  我推荐使用Thread.currentThread().getContextClassLoader().getResource("")来得到当前的classpath的绝对路径的URI表示法。

  Web应用程序中资源的寻址

  上文中说过,当前用户目录,即相对于System.getProperty("user.dir")返回的路径。

  对于JavaEE服务器,这可能是服务器的某个路径,这个并没有统一的规范!

  而不是我们发布的Web应用程序的根目录!

  这样,在Web应用程序中,我们绝对不能使用相对于当前用户目录的相对路径。

  在Web应用程序中,我们一般通过ServletContext.getRealPath("/")方法得到Web应用程序的根目录的绝对路径。

  这样,我们只需要提供相对于Web应用程序根目录的路径,就可以构建出定位资源的绝对路径。

  这是我们开发Web应用程序时一般所采取的策略。

posted @ 2009-07-19 22:18 tmrp 阅读(75) 评论(0) 编辑

对于Java开发人员,多线程应该是必须熟练应用的知识点,特别是开发基于Java语言的产品。本文将深入浅出的表述Java多线程的知识点,在后续的系列里将侧重于Java5由Doug Lea教授提供的Concurrent并行包的设计思想以及具体实现与应用。

如何才能深入浅出呢,我的理解是带着问题,而不是泛泛的看。所以该系列基本以解决问题为主,当然我也非常希望读者能够提出更好的解决问题的方案以及提出更多的问题。由于水平有限,如果有什么错误之处,请大家提出,共同讨论,总之,我希望通过该系列我们能够深入理解Java多线程来解决我们实际开发的问题。

作为开发人员,我想没有必要讨论多线程的基础知识,比如什么是线程? 如何创建等 ,这些知识点是可以通过书本和Google获得的。本系列主要是如何理深入解多线程来帮助我们平时的开发,比如线程池如何实现? 如何应用锁等。

(1)方法Join是干啥用的? 简单回答,同步,如何同步? 怎么实现的? 下面将逐个回答。

自从接触Java多线程,一直对Join理解不了。JDK是这样说的:join public final void join(long millis)throws InterruptedException Waits at most millis milliseconds for this thread to die. A timeout of 0 means to wait forever.大家能理解吗? 字面意思是等待一段时间直到这个线程死亡,我的疑问是那个线程,是它本身的线程还是调用它的线程的,上代码:

package concurrentstudy;
/**
*
* @author vma
*/
public class JoinTest {
public static void main(String[] args) {
Thread t = new Thread(new RunnableImpl());
t.start();
try {
t.join(1000);
System.out.println("joinFinish");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();

}
}
}
class RunnableImpl implements Runnable {

@Override
public void run() {
try {
System.out.println("Begin sleep");
Thread.sleep(1000);
System.out.println("End sleep");
} catch (InterruptedException e) {
e.printStackTrace();
}

}
}
结果是:
Begin sleep
End sleep
joinFinish
明白了吧,当main线程调用t.join时,main线程等待t线程,等待时间是1000,如果t线程Sleep 2000呢
public void run() {
try {
System.out.println("Begin sleep");
// Thread.sleep(1000);
Thread.sleep(2000);
System.out.println("End sleep");
} catch (InterruptedException e) {
e.printStackTrace();
}

}
结果是:
Begin sleep
joinFinish
End sleep
也就是说main线程只等1000毫秒,不管T什么时候结束,如果是t.join()呢, 看代码:
public final void join() throws InterruptedException {
join(0);
}
就是说如果是t.join() = t.join(0) 0 JDK这样说的 A timeout of 0 means to wait forever 字面意思是永远等待,是这样吗?
其实是等到t结束后。
这个是怎么实现的吗? 看JDK代码:
/**
* Waits at most <code>millis</code> milliseconds for this thread to
* die. A timeout of <code>0</code> means to wait forever.
*
* @param millis the time to wait in milliseconds.
* @exception InterruptedException if any thread has interrupted
* the current thread. The <i>interrupted status</i> of the
* current thread is cleared when this exception is thrown.
*/
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;

if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}

if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
} 其实Join方法实现是通过wait(小提示:Object 提供的方法)。 当main线程调用t.join时候,main线程会获得线程对象t的锁(wait 意味着拿到该对象的锁),调用该对象的wait(等待时间),直到该对象唤醒main线程,比如退出后。

这就意味着main 线程调用t.join时,必须能够拿到线程t对象的锁,如果拿不到它是无法wait的,刚开的例子t.join(1000)不是说明了main线程等待1秒,如果在它等待之前,其他线程获取了t对象的锁,它等待时间可不就是1毫秒了。上代码介绍:

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package concurrentstudy;
/**
*
* @author vma
*/
public class JoinTest {
public static void main(String[] args) {
Thread t = new Thread(new RunnableImpl());
new ThreadTest(t).start();
t.start();
try {
t.join();
System.out.println("joinFinish");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();

}
}
}
class ThreadTest extends Thread {

Thread thread;

public ThreadTest(Thread thread) {
this.thread = thread;
}

@Override
public void run() {
holdThreadLock();
}

public void holdThreadLock() {
synchronized (thread) {
System.out.println("getObjectLock");
try {
Thread.sleep(9000);

} catch (InterruptedException ex) {
ex.printStackTrace();
}
System.out.println("ReleaseObjectLock");
}

}
}

class RunnableImpl implements Runnable {

@Override
public void run() {
try {
System.out.println("Begin sleep");
Thread.sleep(2000);
System.out.println("End sleep");
} catch (InterruptedException e) {
e.printStackTrace();
}


}
}

在main方法中 通过new ThreadTest(t).start();实例化ThreadTest 线程对象, 它在holdThreadLock()方法中,通过 synchronized (thread),获取线程对象t的锁,并Sleep(9000)后释放,这就意味着,即使
main方法t.join(1000),等待一秒钟,它必须等待ThreadTest 线程释放t锁后才能进入wait方法中,它实际等待时间是9000+1000 MS
运行结果是:
getObjectLock
Begin sleep
End sleep
ReleaseObjectLock
joinFinish

posted @ 2009-07-19 21:33 tmrp 阅读(211) 评论(0) 编辑
CDN

WIKI的解释:

The capacity sum of strategically placed servers can be higher than the network backbone capacity. This can result in an impressive increase in the number of concurrent users. For instance, when there is a 10 Gbit/s network backbone and 100 Gbit/s central server capacity, only 10 Gbit/s can be delivered. But when 10 servers are moved to 10 edge locations, total capacity can be 10*10 Gbit/s.

Strategically placed edge servers decrease the load on interconnects, public peers, private peers and backbones, freeing up capacity and lowering delivery costs. It uses the same principle as above. Instead of loading all traffic on a backbone or peer link, a CDN can offload these by redirecting traffic to edge servers.

CDNs deliver content over TCP and UDP connections. TCP throughput over a network is impacted by both latency and packet loss. In order to reduce both of these parameters, CDNs traditionally place servers as close to the edge networks that users are on as possible. Theoretically the closer the content the faster the delivery, although network distance may not be the factor that leads to best performance. End users will likely experience less jitter, fewer network peaks and surges, and improved stream quality - especially in remote areas. The increased reliability allows a CDN operator to deliver HD quality content with high Quality of Service, low costs and low network load.

CDNs can dynamically distribute assets to strategically placed redundant core, fallback and edge servers. CDNs can have automatic server availability sensing with instant user redirection. A CDN can offer 100% availability, even with large power, network or hardware outages.

CDN technologies give more control of asset delivery and network load. They can optimize capacity per customer, provide views of realtime load and statistics, reveal which assets are popular, show active regions and report exact viewing details to the customers. These usage details are an important feature that a CDN provider must provide, since the usage logs are no more available at the content source server after it has been plugged into the CDN, because the connections of end-users are now served by the CDN edges instead of the content source.

 

CDN的全称是内容分发网络。其目的是通过在现有的Internet中增加一层新的网络架构,将网站的内容发布到最接近用户的网络“边缘”,使用户可以就近取得所需的内容,提高用户访问网站的响应速度。

CDN有别于镜像,因为它比镜像更智能,或者可以做这样一个比喻:CDN=更智能的镜像+缓存+流量导流。因而,CDN可以明显提高Internet网络中信息流动的效率。从技术上全面解决由于网络带宽小、用户访问量大、网点分布不均等问题,提高用户访问网站的响应速度。

随着目前宽带网络建设的迅猛发展,其应用越来越丰富,使得宽带用户迅速增加,对骨干网构成了极大的压力。其中,占用网络带宽最大的流媒体应用和软件下载业务占了很大比重,且该比例还会随着宽带的普及而迅速增长。对于当前应用而言,减少访问流量的拥塞及用户的访问响应时间,是一个亟待解决的问题。于是,CDN(内容分发网络)网络出现了。

传统的访问模式存在几个严重影响用户访问效率和质量的环节:

●传统的DNS解析过程在将主机域名转换为IP地址时,并不预先判断该服务器是否正常工作,若该服务器已停机,便会造成服务中断。

●互联网缺乏一个专门的中央管理结构,以及产品和技术标准。因此,不同网络间的兼容以及不同网络运营商/ISP之间的传输瓶颈等问题使得数据的流通受到限制。

●现有的互联网以数据包传输为基础,任何一个数据包的丢失或出错都必须重新发送,从而导致延迟。

●现有的路由技术以路由器工作状态的历史数据为依据来确定当前数据包的传输路径,这往往会导致数据传输所经过的路径并不是当前最佳路径。

CDN系统通过在网络各处放置节点服务器,构成在现有互联网基础之上的智能虚拟网络层,能尽量避开互联网上可能影响数据传输速度和稳定性等瓶颈问题,使内容传输的更快、更稳。CDN系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离、响应时间等综合信息,将用户的请求重新导向离用户最近的服务节点上。对用户来说,通过CDN系统,不但使得到响应的时间被大大缩短,而且连接质量也大大提高,从而有效提高了上网访问的总体性能。对于网络运营商而言,则大大的减小骨干网的压力,将对骨干网压力最大的流媒体内容和下载业务放置到网络的边缘。

CDN的关键技术

(1)双重认证技术

系统中提供了基于流媒体服务内核的认证插件,以验证用户是否有效登录。每当用户请求某个节目流时,在流媒体服务内核上,就会对用户身份进行一次确认,如果用户是从正常途径访问的,则可播出该节目流,否则,流服务器将拒绝为用户提供该节目流。利用基于流媒体服务内核的认证插件,可有效地防止用户利用StreamBox等工具来下载流媒体内容。

(2)负载均衡

包括本地服务器和广域网上各个CDN节点之间的负载均衡,根据实际的流量和负荷状况,将用户的请求在不同服务器之间合理分配。

系统通过节目的自动发布、分发和调度,将一些热门的节目内容分布到多台视频服务器上,用户在登录时,就近访问视频服务器,以达到平摊负载的目的。在系统的应用服务器上,将实时登记各台视频服务器当前的网络流量,并根据其他一些用户定义的策略,计算出各视频服务器当前的负载加权指数,该指数说明了服务器当前的负载情况,应用服务器对多台视频服务器的另权指数进行排序。当用户访问宽频网站并进行点播时,通过相应认证后,应用服务器开始为用户分配视频服务器资源。此时,优先选择负载最轻的服务器为用户服务。

(3)内容分发

为使节目的分布合理,使尽可能多的用户点播能够路由到用户最近的媒体终端,CDN系统可提供如下的节目分布策略:按点播率的大小分布、根据节目的更新时间、推荐度进行分发和淘汰,也可支持管理员进行指定文件的分布。

CDN的网络结构

对于宽带信息源网络建设的结构,必须着重考虑应用的布局合理性,尽量将应用推向用户端旁路应用的数据流量,避免造成骨干网络的拥塞。

宽带应用网络支撑平台CDN可简单的分为核心层和接入层。

(1)核心层

核心层作为CDN网络层次结构中的顶端,核心节点是整个CDN网络运行、管理和维护的核心,所有的用户内容请求都会由核心节点进入CDN网络,并由CDN网络根据用户和网络的实际情况,为用户指定一个合理的CDN接入层节点进行服务。

作为CDN网络的核心节点可不直接参与对用户的服务,而是作为CDN运作的中枢,完成如下的主要功能:

a)负责所有用户的内容请求根据用户的信息做出准确的用户就近性判断,并根据判断的结果,将用户的请求分发到指定的分节点。

b)负责CDN的内容分发管理把需要服务的内容通过合适的格式和方式,分发到所有的骨干CDN节点。

(2)接入层

接入层作为CDN网络的边缘层,强调对用户的分布式服务,主要完成的功能包括:

●流媒体平台的缓存节点,提供分区高速内容缓存;

●广播业务分布点,提供两级应用广播服务;

●部分应用前端分布节点;

●通过分布的服务机制,提高服务能力,实现对客户服务的需求。

CDN的业务功能

a)静态内容发布 向网络用户提供迅速、可靠的内容发布服务,对访问用户的请求就近响应。

b)改善网站服务质量 CDN系统中先进的内容路由及网管系统实时将网站的每位用户引导至最佳的一个服务节点,网站的内容则由该节点传达给网络用户。

c)缓解数据风暴 CDN可有效减少网站服务器的负荷,防止网站热点信息内容被频繁点击时出现问题。

d)稳定的服务性能 通过先进的负载均衡技术,CDN可确保其系统运行在最优化状态。

此外,先进的网管系统可对服务器进行实时检测,确保其随时处于正常、健康的工作状态。如有问题发生,则立即切换至备份服务器,以保证用户的连续访问,为解决故障赢得宝贵的时间。

CDN的业务应用

(1)VOD视频点播系统

VOD是视频点播技术的简称,也称交互式电视点播系统,可根据用户的需要播放相应的视频节目,从根本上改变用户过去被动式看电视的不足。

系统提供基于流媒体方式的点播业务,流媒体的后台支持如MPEG1/2/4、REALSERVER和微软的MEDIASERVER,用户在进行视频点播时,可很方便地实现按类别的节目浏览、各类关键字进行节目查询、查看节目排行表、输入自己的影评、查看别人的影评、进行节目预览等操作。

(2)远程教学系统

在CDN应用平台上,可利用直播功能实现同步教学内容的网上直播,同时提供自动录播功能录制成课件;也可制作多媒体课件并发布到课件点播服务器上,实现基于多媒体系统的远程教育。此外,还可提供网络互动交流功能,方便学生和教师进行文字、语音、视频等多媒体交流。

(3)远程医疗系统

在CDN应用平台上,利用直播功能实现中心医院与基层医院就疑难病症进行会诊、指导治疗与护理、对基层医务人员的医学培训等。远程医疗对于一些中、小医院有着重要的意义,即可同时得到大医院的医学专家的咨询和会诊。

(4)多媒体互动广告插播

多媒体广告插播功能对于一个商业化运营的系统极为重要,可作为VOD业务的支撑手段和重要补充。在CDN应用平台中,提供完善的广告插播功能,包括流媒体广告插播、文字广告插播、FLASH广告插播等。

除此之外,它还有其他具有行业特色的应用,如大型网站新闻发布、大型游戏网站分布、大型活动网上直播系统等。

VOD系统设计

(1)核心节点系统设计

核心包括以下子系统:WEB服务子系统、认证服务器、CDN调度/下载服务器、流媒体播出服务子系统、DRM认证服务子系统、数据库服务子系统、后备存储NAS系统、内部管理服务子系统等。

1)WEB服务器主要是为用户提供宽带内容网站WEB服务。

2)CDN资源调度服务器是CDN调度的核心,通过该服务器将网络存储设备上的节目分发到各个视频服务器上。

3)视频服务器可根据不同的应用需要提供不同的并发能力,以同时服务本地的宽带用户。

a)内存要求 服务器上需要至少30MB的预留内存,另外视频每Kbit/s流量至少需要12KB的内存。250并发节目流的视频需要的最少内存为:30MB+12KB×250×500Kbit/s=1.53GB,因此需配置2GB,以为将来扩展留出余量。按500Kbit/s流速率播出节目时,每小时节目需要的磁盘存储容量为500Kbit/s×3600秒/8/1000=225MB。在每台视频服务器上,若配置了4×73GB=292GB的磁盘阵列,能存储1300小时的节目。

b)网卡配置 若节目采用MEDIA格式的流媒体传输,传输流速率为28.8Kbit/s到10Mbit/s,当传输流速率在500Kbit/s左右时能提供达到SVCD质量的视频传输效果,并且能方便ADSL客户进行点播。250个500Kbit/s的节目流需占用250×500Kbit/s=125Mbit/s的网络带宽,但在网络传输时,效率一般只有70%左右,因此,需要在视频服务器上配置1块1000M以太网卡。

c)带宽需求 若核心节点采用10台视频服务器,提供10×250=2500个并发节目流的服务能力。按各节目流500Kbit/s计算,核心节点实际进行视频码流输出所需网络带宽为500K×2500=1.25G。

4)DRM认证服务器主要负责对同时在线访问的用户进行身份验证。本系统中,采用数字版权管理(DRM),主要用以对流媒体节目的内容进行保护。在以往,当系统不采用DRM保护时,用户通过各种途径盗用媒体资源链接或下载媒体内容后,便可免费使用媒体内容,或进行再次分发,造成运营商的巨大损失。而采用DRM系统后,DRM打包机器将根据系统的加密算法和密钥对媒体内容进行加密,此后再将媒体内容通过各种载体(如CD-ROM、媒体服务器等)进行发布;当用户得到加密的媒体内容后,必须先到发放节目的供应商的认证中心进行身份认证和缴纳相应的费用,才可得到授权的解密密钥,媒体播放器利用这个解密密钥将媒体内容进行解密后,便可以播放了。

由于DRM对媒体内容的加密可包括静态的文件或动态的节目流,因此,十分便于在各种场合应用,可对在线的视频直播和点播节目进行管理。同时,也可提供加密节目下载,但只有授权的用户才能解开节目进行观看。

5)数据库服务器用于用户的信息资料存储,并能同时满足用户对数据库的并发访问。

6)NAS网络存储设备解决服务器存储方式下带来的存取等瓶颈问题。它将信息存储设备与服务器分开,网络用户可通过网络实现对存储设备的直接存取访问,把存储设备当作标准网络设备,进行直接存取。

在各视频服务器上,配置的SCSI磁盘阵列,按照80/20的比例,将这部分空间用于存储全系统中20%左右的热门节目,而剩下的80%的冷门节目则由网络存储设备存储,只有在需要时,才会被调度到各视频服务器上去。因此,网络存储设备的要求主要是容量大,对I/0输出等则要求不高,主要用于后备节目的存放,并通过CDN调度服务器分发到各个流服务器上。

(2)分发节点设计

在边缘分发节点,提供500个500K的并发节目流输出,因此,需要两台视频服务器。每台视频服务器提供250个并发节目流,需要250×500K=125Mbit/s的网络带宽资源,至少需要配置2FE。


 来自http://www.fundfund.cn/ 详文参考:http://www.fundfund.cn/news_2008618_26002.htm

 

posted @ 2009-07-19 14:24 tmrp 阅读(13) 评论(0) 编辑
Unchecked exceptions :
  • represent defects in the program (bugs) - often invalid arguments passed to a non-private method. To quote from The Java Programming Language, by Gosling, Arnold, and Holmes : "Unchecked runtime exceptions represent conditions that, generally speaking, reflect errors in your program's logic and cannot be reasonably recovered from at run time."
  • are subclasses of RuntimeException, and are usually implemented using IllegalArgumentException, NullPointerException, or IllegalStateException
  • a method is not obliged to establish a policy for the unchecked exceptions thrown by its implementation (and they almost always do not do so)
Checked exceptions :
  • represent invalid conditions in areas outside the immediate control of the program (invalid user input, database problems, network outages, absent files)
  • are subclasses of Exception
  • a method is obliged to establish a policy for all checked exceptions thrown by its implementation (either pass the checked exception further up the stack, or handle it somehow)
It is somewhat confusing, but note as well that RuntimeException (unchecked) is itself a subclass of Exception (checked).
posted @ 2009-07-18 21:16 tmrp 阅读(77) 评论(0) 编辑
我们都知道,在JDK1.5之前,Java中要进行业务并发时,通常需要有程序员独立完成代码实现,而当针对高质量Java多线程并发程序设计时,为防止死蹦等现象的出现,比如使用java之前的wait()、notify()和synchronized等,每每需要考虑性能、死锁、公平性、资源管理以及如何避免线程安全性方面带来的危害等诸多因素,往往会采用一些较为复杂的安全策略,加重了程序员的开发负担.万幸的是,在JDK1.5出现之后,Sun大神终于为我们这些可怜的小程序员推出了java.util.concurrent工具包以简化并发完成。开发者们借助于此,将有效的减少竞争条件(race conditions)和死锁线程。concurrent包很好的解决了这些问题,为我们提供了更实用的并发程序模型。


java.util.concurrent下主要的接口和类:

Executor:具体Runnable任务的执行者。

ExecutorService:一个线程池管理者,其实现类有多种,比如普通线程池,定时调度线程池ScheduledExecutorService等,我们能把一个

Runnable,Callable提交到池中让其调度。

Future:是与Runnable,Callable进行交互的接口,比如一个线程执行结束后取返回的结果等等,还提供了cancel终止线程。

BlockingQueue:阻塞队列。

下面我写一个简单的事例程序:

FutureProxy.java
  1. package org.test.concurrent;   
  2. /** *//**  
  3. * <p>Title: LoonFramework</p>  
  4. * <p>Description:利用Future模式进行处理</p>  
  5. * <p>Copyright: Copyright (c) 2007</p>  
  6. * <p>Company: LoonFramework</p>  
  7. * @author chenpeng    
  8. * @email:ceponline@yahoo.com.cn   
  9. * @version 0.1  
  10. */  
  11. import java.lang.reflect.InvocationHandler;   
  12. import java.lang.reflect.Method;   
  13. import java.lang.reflect.Proxy;   
  14. import java.util.concurrent.Callable;   
  15. import java.util.concurrent.ExecutorService;   
  16. import java.util.concurrent.Executors;   
  17. import java.util.concurrent.Future;   
  18. import java.util.concurrent.ThreadFactory;   
  19.   
  20. public abstract class FutureProxy<T> {   
  21.   
  22.     private final class CallableImpl implements Callable<T> {   
  23.   
  24.         public T call() throws Exception {   
  25.             return FutureProxy.this.createInstance();   
  26.         }   
  27.     }   
  28.   
  29.     private static class InvocationHandlerImpl<T> implements InvocationHandler {   
  30.   
  31.         private Future<T> future;   
  32.            
  33.         private volatile T instance;   
  34.            
  35.         InvocationHandlerImpl(Future<T> future){   
  36.             this.future = future;   
  37.         }   
  38.            
  39.         public Object invoke(Object proxy, Method method, Object[] args)   
  40.                 throws Throwable {   
  41.             synchronized(this){   
  42.                 if(this.future.isDone()){   
  43.                     this.instance = this.future.get();   
  44.                 }else{   
  45.                     while(!this.future.isDone()){   
  46.                         try{   
  47.                             this.instance = this.future.get();   
  48.                         }catch(InterruptedException e){   
  49.                             Thread.currentThread().interrupt();   
  50.                         }   
  51.                     }   
  52.                 }   
  53.                    
  54.                 return method.invoke(this.instance, args);   
  55.             }   
  56.         }   
  57.     }   
  58.   
  59.     /** *//**  
  60.      * 实现java.util.concurrent.ThreadFactory接口  
  61.      * @author chenpeng  
  62.      *  
  63.      */  
  64.     private static final class ThreadFactoryImpl implements ThreadFactory {   
  65.   
  66.         public Thread newThread(Runnable r) {   
  67.             Thread thread = new Thread(r);   
  68.             thread.setDaemon(true);   
  69.             return thread;   
  70.         }   
  71.     }   
  72.   
  73.     private static ExecutorService service = Executors.newCachedThreadPool(new ThreadFactoryImpl());   
  74.   
  75.     protected abstract T createInstance();   
  76.   
  77.     protected abstract Class<? extends T> getInterface();   
  78.        
  79.     /** *//**  
  80.      * 返回代理的实例  
  81.      * @return  
  82.      */  
  83.     @SuppressWarnings("unchecked")   
  84.     public final T getProxyInstance() {   
  85.         Class<? extends T> interfaceClass = this.getInterface();   
  86.         if (interfaceClass == null || !interfaceClass.isInterface()) {   
  87.             throw new IllegalStateException();   
  88.         }   
  89.   
  90.         Callable<T> task = new CallableImpl();   
  91.   
  92.         Future<T> future = FutureProxy.service.submit(task);   
  93.   
  94.         return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(),   
  95.                 new Class<?>[] { interfaceClass }, new InvocationHandlerImpl(future));   
  96.     }   
  97. }  

Test.java
  1. package org.test.concurrent;   
  2.   
  3. import java.util.Calendar;   
  4.   
  5. /** *//**  
  6. * <p>Title: LoonFramework</p>  
  7. * <p>Description:</p>  
  8. * <p>Copyright: Copyright (c) 2007</p>  
  9. * <p>Company: LoonFramework</p>  
  10. * @author chenpeng    
  11. * @email:ceponline@yahoo.com.cn   
  12. * @version 0.1  
  13. */  
  14. interface DateTest{   
  15.   
  16.     String getDate();   
  17. }   
  18.   
  19. class DateTestImpl implements DateTest{   
  20.        
  21.      private String _date=null;   
  22.         
  23.     public DateTestImpl(){   
  24.         try{   
  25.             _date+=Calendar.getInstance().getTime();   
  26.             //设定五秒延迟   
  27.             Thread.sleep(5000);   
  28.         }catch(InterruptedException e){   
  29.         }   
  30.     }   
  31.        
  32.     public String getDate() {   
  33.   
  34.         return "date "+_date;   
  35.     }   
  36. }   
  37.   
  38. class DateTestFactory extends FutureProxy<DateTest>{   
  39.   
  40.     @Override  
  41.     protected DateTest createInstance() {   
  42.         return new DateTestImpl();   
  43.     }   
  44.   
  45.     @Override  
  46.     protected Class<? extends DateTest> getInterface() {   
  47.         return DateTest.class;   
  48.     }   
  49. }   
  50.   
  51. public class Test{   
  52.   
  53.     public  static void main(String[] args) {   
  54.        
  55.         DateTestFactory factory = new DateTestFactory();   
  56.         DateTest[] dts = new DateTest[100];   
  57.         for(int i=0;i<dts.length;i++){   
  58.             dts[i]=factory.getProxyInstance();   
  59.         }   
  60.         //遍历执行   
  61.         for(DateTest dt : dts){   
  62.             System.out.println(dt.getDate());   
  63.         }   
  64.            
  65.     }   
  66. }  

    

posted @ 2009-07-17 20:06 tmrp 阅读(804) 评论(0) 编辑

 

import java.io.IOException;
/*
 * 守护线程在没有用户线程可服务时自动离开
 * 在Java中比较特殊的线程是被称为守护(Daemon)线程的低级别线程。
 * 这个线程具有最低的优先级,用于为系统中的其它对象和线程提供服务。
 * 将一个用户线程设置为守护线程的方式是在线程对象创建之前调用线程对象的setDaemon方法。
 * 典型的守护线程例子是JVM中的系统资源自动回收线程,
 * 我们所熟悉的Java垃圾回收线程就是一个典型的守护线程,
 * 当我们的程序中不再有任何运行中的Thread,
 * 程序就不会再产生垃圾,垃圾回收器也就无事可做,
 * 所以当垃圾回收线程是Java虚拟机上仅剩的线程时,Java虚拟机会自动离开。
 * 它始终在低级别的状态中运行,用于实时监控和管理系统中的可回收资源。
 * 守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。
 * 也就是说守护线程不依赖于终端,但是依赖于系统,与系统“同生共死”。
 * 那Java的守护线程是什么样子的呢。
 * 当JVM中所有的线程都是守护线程的时候,JVM就可以退出了;
 * 如果还有一个或以上的非守护线程则JVM不会退出。
 */
public class testThread extends Thread {
   
    public testThread() {
    }
    /** *//**
     * 线程的run方法,它将和其他线程同时运行
     */
    public void run(){
        for(int i = 1; i <= 100; i++){
            try{
                Thread.sleep(100);
               
            } catch (InterruptedException ex){
                ex.printStackTrace();
            }
            System.out.println(i);
        }
    }
    public static void main(String [] args){
     testThread test = new testThread();
        test.setDaemon(true);
        test.start();
        System.out.println("isDaemon = " + test.isDaemon());
        try {
            System.in.read(); // 接受输入,使程序在此停顿,一旦接收到用户输入,main线程结束,守护线程自动结束
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}
posted @ 2009-07-17 14:31 tmrp 阅读(315) 评论(0) 编辑