﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-聂永的博客-随笔分类-Java</title><link>http://www.blogjava.net/yongboy/category/54839.html</link><description>记录工作/学习的点点滴滴。</description><language>zh-cn</language><lastBuildDate>Mon, 01 Jun 2015 06:30:02 GMT</lastBuildDate><pubDate>Mon, 01 Jun 2015 06:30:02 GMT</pubDate><ttl>60</ttl><item><title>哈，又一款超级简单的队列（MQ）实现方案来了~</title><link>http://www.blogjava.net/yongboy/archive/2012/03/20/372308.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Tue, 20 Mar 2012 12:30:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2012/03/20/372308.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/372308.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2012/03/20/372308.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/372308.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/372308.html</trackback:ping><description><![CDATA[<div style="text-indent: 2em;">
开源的消息队列已经很多了，但大部分很重，实际环境下，很多可能只是使用到了一点功能而已，杀鸡使用牛刀，着实有些浪费了。很多时候，我们只想要一片绿叶，但它们给了我们整个的春天，很难消化。本着DIR精神， 也琢磨了一个超级简单的队列实现。</div>
<div style="text-indent: 2em;">
说是超级简单，嗯，绝对是超级简单，队列的存储采用Redis进行持久化存储，采用Netty提供HTTP方式的队列的出/入。Redis的客户端采用的Jedis。然后呢，然后就没了啊。</div>
<h3>
 一。Redis</h3>
<div style="text-indent: 2em;">
Redis内置订阅发布模型(Publish/Subscribe),其缺陷是，不存储，一旦订阅者断线，将无法接收到消息，再次连接上之后，在断线期间发布者发布的消息都是无法获取到的。只能采用list数组实现，采用rpush/lpop组合命令来实现先进先出的队列模型，当然redis也提供了阻塞版本的blpush/brpush/blpop/brpop等，就看我们实际环境下如何使用了。</div>
<div style="text-indent: 2em;">
JAVA客户端使用Jedis，提供接口也很丰富。但要注意的是，需要使用连接池，否则在大数量的情况下，有可能jedis的连接不够用。
<pre>private static JedisPool pool;
 static {
  ResourceBundle bundle = ResourceBundle.getBundle("redis");
  if (bundle == null) {
   throw new IllegalArgumentException(
     "cannot find the SignVerProp.properties");
  }
  JedisPoolConfig config = new JedisPoolConfig();
  config.setMaxActive(Integer.valueOf(bundle
    .getString("redis.pool.maxActive")));
  config.setMaxIdle(Integer.valueOf(bundle
    .getString("redis.pool.maxIdle")));
  config.setMaxWait(Integer.valueOf(bundle
    .getString("redis.pool.maxWait")));
  pool = new JedisPool(config, bundle.getString("redis.server"),
    Integer.valueOf(bundle.getString("redis.port")));
 }
</pre>
</div>
<h3>
 二。Netty</h3>
<div style="text-indent: 2em;">
很成熟的NIO框架，用它来提供HTTP方式的队列的出入。嗯，目前只提供HTTP方式的入队列，出队列等。<br />HTTP形式为：<strong>http://服务器名称:端口/队列操作原语/队列名称?msg=消息内容</strong>
<br />队列操作原语，只有get和put；get为出队列，put为入队列。<br />返回为json：
{s:0, m:'错误消息/消息内容'}
<br />s为success的缩写，值为0，意味着false，1对应成功。
m为message的缩写，错误消息/消息内容，添加消息时，会返回插入消息对应的数目
默认采用UTF-8。</div>
<div style="text-indent: 2em;">
入队列：http://localhost:8080/put/demo?msg=消息内容
<br />出队列：http://localhost:8080/get/demo
HTTP方式，特别适合局域网之间，消息数据的推送。</div>
<div style="text-indent: 2em;">
</div>
<h3>
 三。入口解读</h3>
<div style="text-indent: 2em;">
采用了QueueDaemon封装了netty代码：
<script src="https://gist.github.com/2130999.js?file=QueueDaemon.java">
</script>
调用很简单，程序启动的入口：
<script src="https://gist.github.com/2131009.js?file=QueueServer.java">
</script>
而HTTP方式队列请求处理器为HttpRequestHandler：
<script src="https://gist.github.com/2131025.js?file=HttpRequestHandler.java">
</script></div>
<h3>
 四。队列处理器</h3>
<div style="text-indent: 2em;">
这个很简单，直接采用Jedis客户端即可，这里一直占用一个连接，不释放。
<script src="https://gist.github.com/2131062.js?file=QueueHandler.java">
</script></div>
<h3>
 五。ab压力测试</h3>
<div style="text-indent: 2em;">
本机配置：Pentium(R) Dual-Core CPU E5200 2.50GHz，<span style="text-indent: 2em;">2.00 GB内存</span><span style="text-indent: 2em;">，Windows XP系统，redis-2.4.5-win32 32版本（非linux版本），都在一台机器上运行。</span>
<strong>插入 512 bytes 文本消息队列: 1781.24 requests/sec</strong>
<pre>D:\Apache2.2\bin&gt;ab -c 10 -n 100000 "http://localhost:8080/put/demo?msg=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
This is ApacheBench, Version 2.3 &lt;$Revision: 655654 $&gt;
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
Completed 10000 requests
Completed 20000 requests
Completed 30000 requests
Completed 40000 requests
Completed 50000 requests
Completed 60000 requests
Completed 70000 requests
Completed 80000 requests
Completed 90000 requests
Completed 100000 requests
Finished 100000 requests
Server Software:
Server Hostname:        localhost
Server Port:            8080
Document Path:          /put/demo?msg=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Document Length:        12 bytes
Concurrency Level:      10
Time taken for tests:   56.141 seconds
Complete requests:      100000
Failed requests:        99991
   (Connect: 0, Receive: 0, Length: 99991, Exceptions: 0)
Write errors:           0
Total transferred:      8188895 bytes
HTML transferred:       1588895 bytes
Requests per second:    1781.24 [#/sec] (mean)
Time per request:       5.614 [ms] (mean)
Time per request:       0.561 [ms] (mean, across all concurrent requests)
Transfer rate:          142.45 [Kbytes/sec] received
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   1.7      0      16
Processing:     0    5  10.7      0     781
Waiting:        0    5  10.4      0     766
Total:          0    6  10.8      0     781
Percentage of the requests served within a certain time (ms)
  50%      0
  66%     16
  75%     16
  80%     16
  90%     16
  95%     16
  98%     16
  99%     16
 100%    781 (longest request)
</pre>
<strong>插入 512 bytes 文本消息队列(添加Keep-Alive支持): 1875.18 requests/sec</strong>
<pre>D:\Apache2.2\bin&gt;ab -k -c 10 -n 100000 "http://localhost:8080/put/demo?msg=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
This is ApacheBench, Version 2.3 &lt;$Revision: 655654 $&gt;
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
Completed 10000 requests
Completed 20000 requests
Completed 30000 requests
Completed 40000 requests
Completed 50000 requests
Completed 60000 requests
Completed 70000 requests
Completed 80000 requests
Completed 90000 requests
Completed 100000 requests
Finished 100000 requests
Server Software:
Server Hostname:        localhost
Server Port:            8080
Document Path:          /put/demo?msg=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Document Length:        17 bytes
Concurrency Level:      10
Time taken for tests:   53.328 seconds
Complete requests:      100000
Failed requests:        0
Write errors:           0
Keep-Alive requests:    0
Total transferred:      8300000 bytes
HTML transferred:       1700000 bytes
Requests per second:    1875.18 [#/sec] (mean)
Time per request:       5.333 [ms] (mean)
Time per request:       0.533 [ms] (mean, across all concurrent requests)
Transfer rate:          151.99 [Kbytes/sec] received
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   1.5      0      16
Processing:     0    5   7.8      0     203
Waiting:        0    5   7.8      0     203
Total:          0    5   7.9      0     203
Percentage of the requests served within a certain time (ms)
  50%      0
  66%      0
  75%     16
  80%     16
  90%     16
  95%     16
  98%     16
  99%     16
 100%    203 (longest request)
</pre>
<strong>获取 512 bytes 消息(With Keep-Alive): 1875.73 requests/sec</strong>
<pre>D:\Apache2.2\bin&gt;ab -k -c 10 -n 100000 "http://localhost:8080/get/demo"
This is ApacheBench, Version 2.3 &lt;$Revision: 655654 $&gt;
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
Completed 10000 requests
Completed 20000 requests
Completed 30000 requests
Completed 40000 requests
Completed 50000 requests
Completed 60000 requests
Completed 70000 requests
Completed 80000 requests
Completed 90000 requests
Completed 100000 requests
Finished 100000 requests
Server Software:
Server Hostname:        localhost
Server Port:            8080
Document Path:          /get/demo
Document Length:        523 bytes
Concurrency Level:      10
Time taken for tests:   53.313 seconds
Complete requests:      100000
Failed requests:        0
Write errors:           0
Keep-Alive requests:    0
Total transferred:      58900000 bytes
HTML transferred:       52300000 bytes
Requests per second:    1875.73 [#/sec] (mean)
Time per request:       5.331 [ms] (mean)
Time per request:       0.533 [ms] (mean, across all concurrent requests)
Transfer rate:          1078.91 [Kbytes/sec] received
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   1.9      0      16
Processing:     0    5   7.5      0      94
Waiting:        0    4   6.9      0      94
Total:          0    5   7.6      0      94
Percentage of the requests served within a certain time (ms)
  50%      0
  66%      0
  75%     16
  80%     16
  90%     16
  95%     16
  98%     16
  99%     16
 100%     94 (longest request)</pre>
</div>
<h3>
 其它问题</h3>
<div style="text-indent: 2em;">
<ol>
<li>暂时对安全/授权没有支持，这个其实很容易实现</li>
<li>队列处理器很简单，直接使用jedis即可</li>
<li>对队列数据进行分片(sharding)，写一个QueueService实现即可</li>
<li>对Redis的内存持久化不放心，采用diskstore存储模式好了，在Redis中配置，不涉及到程序</li>
<li>对队列分布式存储，写一个QueueService实现，其它可不用变化</li>
<li>不适合严格意义上的订阅/发布模型，这里适合多个发布者/单个订阅者环境</li>
<li>HTTP请求返回内容为json格式，xml格式，暂时不需要</li>
<li>局域网环境下，系统之间进行消息的推送/通知，</li>
</ol>
</div>
<div style="text-indent: 2em;">
项目下载地址：<a href="http://code.google.com/p/nettyqueue/" target="_blank">http://code.google.com/p/nettyqueue/</a>
参考资料：
<ol>
<li>
<a href="http://code.google.com/p/httpsqs/" target="_blank">httpsqs</a>
</li>
</ol>
</div><img src ="http://www.blogjava.net/yongboy/aggbug/372308.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2012-03-20 20:30 <a href="http://www.blogjava.net/yongboy/archive/2012/03/20/372308.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Fork/Join模式(JSR166y)手记之Fork/Join模式实现浅析1</title><link>http://www.blogjava.net/yongboy/archive/2012/02/08/370142.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Wed, 08 Feb 2012 13:35:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2012/02/08/370142.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/370142.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2012/02/08/370142.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/370142.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/370142.html</trackback:ping><description><![CDATA[<div style="text-indent: 2em;">对Fork/Join的个人理解要点：<br /><ul><li>fork/join将大的任务分割小的任务，直到小的任务可以使用最简单、直接或者同步的方式处理。</li><li>最小的任务将无法分解</li><li>每一个任务不是线程的实例</li><li>每一个工作线程将是一个隐式的线程实例</li><li>每一个工作线程都会维护自身的一个双向队列（支持FIFO/LIFO）；在任务产生的子任务，会被push进当前工作线程所维护deque队列中，进入队列头部。</li><li>当一个工作线程的双向队列中暂无任务时，它会从随机的工作线程的双向队列的尾部获取一个入队最久的子任务(称之为窃取),take()方式获取，先进先出的规则(FIFO)。</li><li>当一个工作线程遇到一个join的操作，假如可能的话，它会处理其他的任务，直到目标任务被通知需要处理掉。</li><li>当一个工作者线程没有任务可以处理，并且不能从其他工作者线程中窃取的时，它会后退(通过yields,sleeps,或者优先级的调整),稍后重试，直到所有工作线程都会处于空闲状态，所有线程都会阻塞，等到另外的任务在顶层被调用。</li></ul></div><div style="text-indent: 2em;"><a href="http://www.ibm.com/developerworks/cn/java/j-jtp11137.html">Brian Goetz</a> 认为"使用传统的线程池来实现 fork-join 也具有挑战性，因为 fork-join任务将线程生命周期的大部分时间花费在等待其他任务上。这种行为会造成线程饥饿死锁（thread starvation deadlock），除非小心选择参数以限制创建的任务数量，或者池本身非常大。传统的线程池是为相互独立的任务设计的，而且设计中也考虑了潜在的阻塞、粗粒度任务 &#8212; fork-join 解决方案不会产生这两种情况。对于传统线程池的细粒度任务，也存在所有工作线程共享的任务队列发生争用的情况。"</div><div style="text-indent: 2em;">下面谈一谈工作窃取(work stealing)。在Fork/Join中，工作窃取采用了一个被当做栈(Stack)使用的双端队列WorkQueue。双端队列WorkQueue，支持在两端插入和移除元素，和单独的队列(Queue)相比，多了一端。在Fork/Join中工作线程中被当做栈（Stack）来使用，在头部push插入数据，pop获取数。而尾部，可以供需要窃取的工作线程（take()方法）使用。与单向队列相比，减少争用，可以提高性能。</div><div style="text-indent: 2em;"><div class="separator" style="clear: both; text-align: center;"><img src="http://www.blogjava.net/images/blogjava_net/yongboy/stealqueue.png" alt="" height="517" width="364" /></div>WorkQueue的定义：<br /><pre>static final class WorkQueue {<br />   ......<br />}</pre>它既没有继承自Deque又没有继承Queue接口，而是自己独立写了一个双端队列，数组实现。很显然，数组的读取性能要强于链表。<br />看一下ForkJoinPool的默认构造函数:<br /><pre>public ForkJoinPool() {<br />        this(Runtime.getRuntime().availableProcessors(),<br />             defaultForkJoinWorkerThreadFactory, null, false);<br />    }<br /><br />    public static interface ForkJoinWorkerThreadFactory {<br />        public ForkJoinWorkerThread newThread(ForkJoinPool pool);<br />    }<br /><br />    static class DefaultForkJoinWorkerThreadFactory<br />        implements ForkJoinWorkerThreadFactory {<br />        public ForkJoinWorkerThread newThread(ForkJoinPool pool) {<br />            return new ForkJoinWorkerThread(pool);<br />        }<br />    }   <br /></pre>在ForkJoinPool代码初始化时，默认情况下：<br /><pre>defaultForkJoinWorkerThreadFactory =<br />            new DefaultForkJoinWorkerThreadFactory(); </pre>默认情况下，根据当前CPU的数量建立一个ForkJoinWorkerThreadFactory工厂，CPU数量个ForkJoinWorkerThread工作线程。</div><div style="text-indent: 2em;">仔细看一下ForkJoinWorkerThread代码，工作线程继承自Thread：</div><script src="https://gist.github.com/1750798.js?file=ForkJoinWorkerThread.java"></script><br /><div style="text-indent: 2em;">很显然，onStart 和 onTermination为钩子函数，可以被重写，但，需要构造一个新的ForkJoinPool.ForkJoinWorkerThreadFactory来配合使用。比如：<br /><pre>public static void main(String[] args) {<br />  ForkJoinPool.ForkJoinWorkerThreadFactory factory = new  ForkJoinPool.ForkJoinWorkerThreadFactory() {<br />   @Override<br />   public ForkJoinWorkerThread newThread(ForkJoinPool pool) {<br />    return new CustomedForkJoinWorkerThread(pool);<br />   }<br />  };<br /><br />  ForkJoinPool joinPool = new ForkJoinPool(Runtime.getRuntime()<br />    .availableProcessors(), factory, null, false);<br />  // some code here ...<br /> }<br /><br /> private static final class CustomedForkJoinWorkerThread extends<br />   ForkJoinWorkerThread {<br />  protected CustomedForkJoinWorkerThread(ForkJoinPool pool) {<br />   super(pool);<br />  }<br /><br />  @Override<br />  protected void onStart() {<br />   super.onStart();<br /><br />   System.out.println("准备初始化资源...");<br />  }<br /><br />  @Override<br />  protected void onTermination(Throwable exception) {<br />   System.out.println("开始清理资源...");<br /><br />   super.onTermination(exception);<br />  }<br /> }</pre></div><div style="text-indent: 2em;">接着看一下pool.runWorker(this)方法：<br /><pre>final void runWorker(ForkJoinWorkerThread wt) {<br />        WorkQueue w = wt.workQueue;<br />        w.growArray(false);<br />        w.seed = hashId(Thread.currentThread().getId());<br /><br />        do {} while (w.runTask(scan(w)));<br />    }</pre></div><div style="text-indent: 2em;">初始化队列，设置其seed为当前线程ID的哈希值。然后循环执行，当没有任务可获取，自然就退出了。而scan()很复杂，大概功能，从当前队列中获取元素，当前队列为空时，从其他工作线程所持有的队列中窃取一个。都没有时，只能返回null，进而阻止线程活动。</div><div style="text-indent: 2em;">嗯，有时间会再深入WorkQueue队列一些。</div><div style="text-indent: 2em;">&nbsp;&nbsp;</div><div style="text-indent: 2em;">&nbsp;&nbsp;</div><div style="text-indent: 2em;">参考资料:<br /><ol><li><a href="http://www.ibm.com/developerworks/cn/java/j-jtp11137.html" title="_blank">Java 理论与实践: 应用 fork-join 框架</a></li><li><a href="http://www.ibm.com/developerworks/cn/java/j-lo-forkjoin/index.html" target="_blank">JDK 7 中的Fork/Join 模式</a></li><li><br /><a href="http://gee.cs.oswego.edu/dl/papers/fj.pdf" target="_blank">Doug Lea:A Java Fork/Join Framework</a></li></ol></div><img src ="http://www.blogjava.net/yongboy/aggbug/370142.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2012-02-08 21:35 <a href="http://www.blogjava.net/yongboy/archive/2012/02/08/370142.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Fork/Join模式(JSR166y)手记之斐波纳契数列(Fibonacci)求解测试</title><link>http://www.blogjava.net/yongboy/archive/2012/02/07/369571.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Tue, 07 Feb 2012 13:24:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2012/02/07/369571.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/369571.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2012/02/07/369571.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/369571.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/369571.html</trackback:ping><description><![CDATA[<div style="text-indent: 2em;">在参考资料中，对斐波纳契数列(Fibonacci)进行求解来展示RecursiveTask的用法，很好。</div><div style="text-indent: 2em;">另外，在JSR166y演进的过程中，其算法经过调整，导致原示范代码中存在一些问题，需要进行些许调整。历史遗留代码，如下：<br /><pre>Fibonacci f1 = new Fibonacci(n - 1);<br />  f1.fork();<br />  Fibonacci f2 = new Fibonacci(n - 2);<br />  f2.fork();<br /><br />  return f2.join() + f1.join();<br /></pre>但现在已不建议使用。真要如此执行，会一直阻塞等待（至少我本机是如此）。查看RecursiveTask的源代码，也发现示范doc中，两个RecursiveTask类型结果相互汇聚，推荐示范为：</div><div style="text-indent: 2em;"><pre>Fibonacci f1 = new Fibonacci(n - 1);<br />  f1.fork();<br />  Fibonacci f2 = new Fibonacci(n - 2);<br /><br />  return f2.compute() + f1.join();<br /></pre></div><div style="text-indent: 2em;">嗯，这里同时提供一个单线程版本的参考实现，与之作为对比：</div><script src="https://gist.github.com/1709531.js?file=SingleThreadFibonacci.java"></script><br /><div style="text-indent: 2em;">在测试时，发现速度太慢，于是萌生了改进了其算法的想法，于是一个非递归、单线程版本实现出现了：</div><script src="https://gist.github.com/1709539.js?file=ImprovedFibonacci.java"></script><br /><div style="text-indent: 2em;">使用JUNIT 4进行测试类：</div><script src="https://gist.github.com/1709544.js?file=TestFibonacci.java"></script><br /><div style="text-indent: 2em;">该贴的代码，都贴完了，可以预测一下哪一个算法的速度排名吗 ？嗯，贴出运行JUNIT测试输出结果吧：<br /><blockquote>Fork/Join 算法 ...<br />1836311903<br />用时 : 2203<br /><br />单线程递归算法 ...<br />1836311903<br />用时 : 1016<br /><br />单线程改进递增算法 ...<br />1836311903<br />用时  : 0</blockquote>在测试类中，把MAX设置为55或更大的数字，以上两个算法就可能等待过长的时间（实在没有耐心等待那么长时间），而算法三，即使设置再大，也是瞬时完成。<br />上面的测试类中，把results数组以static修饰，公共共享方式，存放在常量区，在速度上会比原始测试代码读取方面更为迅速，快了不少。<br />本机的CPU双核的效果没有体现出来。权威一些的解析：<br /><blockquote>在Java 7 生命周期内，大的（32+）多核系统将大量出现，有了这个框架可以让人们对计算密集型任务获得相对简单的增速方法。目前，forkjoin在如Sun Niagaras和Azuls这样的机器上工作得最好，它们只是即将普及的并行处理器。Forkjoin在标准SMP上工作的也不错。总体来讲，少于4处理器的话你不并能获得太多增速效果&#8212;&#8212;其主要目标是针对成打到成百处理器范围。</blockquote>另一方面，也是任务划分过于细小，优势体现不出来。当然，不是所有的任务都适合Fork/Join模式，以及适合多线程，就看具体任务具体分析了。</div><div style="text-indent: 2em;">参考资料：<br /><ol><li><br /><a href="http://www.ibm.com/developerworks/cn/java/j-lo-forkjoin/">JDK 7 中的 Fork/Join 模式</a><br /></li></ol></div><img src ="http://www.blogjava.net/yongboy/aggbug/369571.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2012-02-07 21:24 <a href="http://www.blogjava.net/yongboy/archive/2012/02/07/369571.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Fork/Join模式(JSR166y)手记之Phaser</title><link>http://www.blogjava.net/yongboy/archive/2012/02/07/369572.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Tue, 07 Feb 2012 09:34:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2012/02/07/369572.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/369572.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2012/02/07/369572.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/369572.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/369572.html</trackback:ping><description><![CDATA[<div style="text-indent: 2em;">这是一个综合了CountDownLatch和CyclicBarrier特性的混合体，官方说灵活性非常高。基本上，只要对上面两个熟悉，那么阅读API，也不难快速上手的。</div><div style="text-indent: 2em;"><strong><a href="http://yaofeng928.iteye.com/">yaofeng928</a></strong> 简单总结其特点：<br /><blockquote>Phaser同时包含CyclicBarrier和CountDownLatch两个类的功能。Phaser的arrive方法将将计数器加1，awaitAdvance将线程阻塞，直到计数器达到目标，这两个方法与CountDownLatch的countDown和await方法相对应；Phaser的arriveAndAwaitAdvance方法将计数器加1的同时将线程阻塞，直到计数器达到目标后继续执行，这个方法对应CyclicBarrier的await方法。<br /><br />除了包含以上两个类的功能外，Phaser还提供了更大的灵活性。CyclicBarrier和CountdownLatch在构造函数指定目标后就无法修改，而Phaser提供了register和deregister方法可以对目标进行动态修改。</blockquote></div><div style="text-indent: 2em;"><a href="http://yaofeng928.iteye.com/">yaofeng928</a>在他的博客文章中也提供了<a href="http://yaofeng928.iteye.com/blog/1136648" target="_blank">测试示范</a>，有兴趣着看看一看。</div><div style="text-indent: 2em;">在参考资料的第二个链接，则非常用心的给出<a href="http://www.oschina.net/question/12_35433" target="_blank">对Phaser的用心解释</a>，绝对值得一看，不过其代码存在些许错误，但对总体理解不产生障碍。</div><br /><div style="text-indent: 2em;">参考资料链接1则给出了，各种使用场景。</div><div style="text-indent: 2em;">别人把自己所有想要理解的，基本都上说出来，不再需要单独写一篇，改成推荐好了。</div><div style="text-indent: 2em;"></div><div style="text-indent: 2em;">参考资料：<br /><ol><li><a href="http://whitesock.iteye.com/blog/1135457" target="_blank">What's New on Java 7 Phaser</a></li><li><a class="item-title" href="http://www.oschina.net/question/12_35433">Java 7: 理解 Phaser</a></li><li><a href="http://yaofeng928.iteye.com/blog/1136648">探索JDK7的并发编程&#8212;&#8212;PHASER</a></li></ol></div><img src ="http://www.blogjava.net/yongboy/aggbug/369572.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2012-02-07 17:34 <a href="http://www.blogjava.net/yongboy/archive/2012/02/07/369572.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Fork/Join模式(JSR166y)手记之ConcurrentLinkedDeque</title><link>http://www.blogjava.net/yongboy/archive/2012/02/06/369573.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Mon, 06 Feb 2012 12:39:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2012/02/06/369573.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/369573.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2012/02/06/369573.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/369573.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/369573.html</trackback:ping><description><![CDATA[<div style="text-indent: 2em;">ConcurrentLinkedDeque是JSR166y中新增的一个无界并发Deque实现，基于已链接节点的、任选范围的双端队列。在迭代时，队列保持弱一致性，但不会抛出ConcurrentModificationException异常。</div><div style="text-indent: 2em;">需要小心，与大多数 collection 不同，size 方法不是一个固定时间操作。由于这些队列的异步特性，确定当前元素的数量需要遍历这些元素。</div><div style="text-indent: 2em;">另外，一些批量操作，诸如 addAll, removeAll, retainAll, containsAll, equals, toArray等，不能够保证会立刻执行。比如通过addAll方法批量提交若干元素，于此同时另一线程在迭代时，可能只能访问到先前存在的元素。</div><div style="text-indent: 2em;">内存一致性效果：当存在其他并发 collection 时，将对象放入 ConcurrentLinkedDeque 之前的线程中的操作 happen-before 随后通过另一线程从 ConcurrentLinkedDeque 访问或移除该元素的操作。 </div><div style="text-indent: 2em;">先前存在一个线程安全并阻塞的LinkedBlockingDeque实现，现在好了，又多了个并发实现，这样和Queue保持一致，并发和阻塞版本都具有了。嗯，果然是好事要成双。</div><div style="text-indent: 2em;">在使用上没有什么可说的，随时查看API DOC，即可。刚开始以为Fork/Join的工作窃取（work stealing）机制内部使用ConcurrentLinkedDeque实现，查看ForkJoinPool源代码时，不曾发现其身影。</div><div style="text-indent: 2em;"><br /><br /><br /><br />参考资料:<br /><ol><li><a href="http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentLinkedDeque.html">Class ConcurrentLinkedDeque</a><e></e></li></ol></div><img src ="http://www.blogjava.net/yongboy/aggbug/369573.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2012-02-06 20:39 <a href="http://www.blogjava.net/yongboy/archive/2012/02/06/369573.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Fork/Join模式(JSR166y)手记之ThreadLocalRandom</title><link>http://www.blogjava.net/yongboy/archive/2012/02/04/369574.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Sat, 04 Feb 2012 03:29:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2012/02/04/369574.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/369574.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2012/02/04/369574.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/369574.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/369574.html</trackback:ping><description><![CDATA[<div style="text-indent: 2em;">ThreadLocalRandom是一个可以独立使用的、用于生成随机数的类。继承自Random，但性能超过Random，所谓&#8220;青出于蓝而胜于蓝&#8221;。其API所提供方法，不多，父类Random具有的，它也一样具有。从表明看，是一个单例模式，其实不然：<br /><pre>private static final ThreadLocal<threadlocalrandom> localRandom =<br />        new ThreadLocal<threadlocalrandom>() {<br />            protected ThreadLocalRandom initialValue() {<br />                return new ThreadLocalRandom();<br />            }<br />    };<br /><br />    ThreadLocalRandom() {<br />        super();<br />        initialized = true;<br />    }<br /><br /><br />    public static ThreadLocalRandom current() {<br />        return localRandom.get();<br />    }<br /></threadlocalrandom></threadlocalrandom></pre>采用ThreadLocal进行包装的Random子类，每线程对应一个ThreadLocalRandom实例。测试代码：<br /><pre>@Test<br /> public void testInstance() {<br />  final ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();<br />  final List<threadlocalrandom> randomList = new ArrayList<threadlocalrandom>();<br />  final Phaser barrier = new Phaser(1);<br />  <br />  new Thread() {<br />   @Override<br />   public void run() {<br />    randomList.add(ThreadLocalRandom.current());<br />    barrier.arrive();<br />   }<br />  }.start();<br /><br />  barrier.awaitAdvance(barrier.getPhase());<br />  if (randomList.isEmpty()) {<br />   throw new NullPointerException();<br />  }<br /><br />  Assert.assertTrue(threadLocalRandom != randomList.get(0));<br /> }</threadlocalrandom></threadlocalrandom></pre></div><div style="text-indent: 2em;">这么一包装，在性能上可以赶超Math.random()，不错。<br /><pre>@Test<br /> public void testSpeed() {<br />  final int MAX = 100000;<br />  ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();<br /><br />  long start = System.nanoTime();<br />  for (int i = 0; i &lt; MAX; i++) {<br />   threadLocalRandom.nextDouble();<br />  }<br />  long end = System.nanoTime() - start;<br />  System.out.println("use time1 : " + end);<br /><br />  long start2 = System.nanoTime();<br />  for (int i = 0; i &lt; MAX; i++) {<br />   Math.random();<br />  }<br />  long end2 = System.nanoTime() - start2;<br />  System.out.println("use time2 : " + end2);<br /><br />  Assert.assertTrue(end2 &gt; end);<br /> }</pre>非规范的性能测试，某次输出结果:<br /><blockquote>use time1 : 3878481<br />use time2 : 8633080</blockquote>性能差别不止两倍啊，哈哈。<br />再看Math.random()，其生成也是依赖于Random类:<br /><pre>private static Random randomNumberGenerator;<br /><br />    private static synchronized void initRNG() {<br />        if (randomNumberGenerator == null) <br />            randomNumberGenerator = new Random();<br />    }<br /><br />    public static double random() {<br />        if (randomNumberGenerator == null) initRNG();<br />        return randomNumberGenerator.nextDouble();<br />    }<br /></pre>很奇怪，性能为什么差那么远呢？可能个各自的next函数不同造成。看一下Random中的next(int bits)方法实现：<br /><pre>protected int next(int bits) {<br />        long oldseed, nextseed;<br />        AtomicLong seed = this.seed;<br />        do {<br />     oldseed = seed.get();<br />     nextseed = (oldseed * multiplier + addend) &amp; mask;<br />        } while (!seed.compareAndSet(oldseed, nextseed));<br />        return (int)(nextseed &gt;&gt;&gt; (48 - bits));<br />    }</pre>而ThreadLocalRandom的重写版本为：<br /><pre>protected int next(int bits) {  <br />        rnd = (rnd * multiplier + addend) &amp; mask;  <br />        return (int) (rnd &gt;&gt;&gt; (48-bits));  <br />    }</pre>相比ThreadLocalRandom的next(int bits)函数实现上更为简练，不存在seed的CAS操作，并且少了很多的运算量。<br />更为详细的机制研读，请阅读参考资料中链接。</div><div style="text-indent: 2em;">另外，ThreadLocalRandom 也提供了易用的，两个数字之间的随机数生成方式。类似于：<br /><blockquote>nextDouble(double least, double bound) <br />nextInt(int least, int bound) <br />nextLong(long least, long bound) </blockquote>随机数的生成范围为 最小值 &lt;= 随机数 &lt; 最大值。可以包含最小值，但不包含最大值。 <br /><pre>@Test<br />public void testHowtoUse(){<br />final ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();<br />final int MAX = 100;<br />int result = threadLocalRandom.nextInt(0, 100);<br />Assert.assertTrue(MAX &gt; result);<br />}</pre></div><div style="text-indent: 2em;">嗯，还有，不支持setSeed方法。</div><div style="text-indent: 2em;">曾经JDK 7中，ThreadLocalRandom 存在随机多个线程随机数生成相同的bug，但最新版本中，已不存在，被修复了,可以放心使用。从现在开始，完全可以使用ThreadLocalRandom替代Random，尤其是在并发、并行、多任务等环境下，会比在多线程环境下使用公共共享的<span class="Apple-style-span" style="font-family: monospace;">Random对象实例更为有效。</span></div><div style="text-indent: 2em;">代码清单：</div><script src="https://gist.github.com/1722196.js?file=RandomTest.java"></script><br /><div style="text-indent: 2em;">参考资料:<br /><ol><li><a href="http://java.dzone.com/articles/java-7-how-write-really-fast" target="_blank">Java 7: How to write really fast Java code</a></li></ol></div><img src ="http://www.blogjava.net/yongboy/aggbug/369574.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2012-02-04 11:29 <a href="http://www.blogjava.net/yongboy/archive/2012/02/04/369574.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Fork/Join模式(JSR166y)手记之TransferQueue/LinkedTransferQueue</title><link>http://www.blogjava.net/yongboy/archive/2012/02/04/369575.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Sat, 04 Feb 2012 03:28:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2012/02/04/369575.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/369575.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2012/02/04/369575.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/369575.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/369575.html</trackback:ping><description><![CDATA[<div style="text-indent: 2em;">TransferQueue是一个继承了 BlockingQueue的接口，并且增加若干新的方法。LinkedTransferQueue是实现类，其定义为一个无界的队列，一样具有先进先出(FIFO : first-in-first-out)的特性。</div><div style="text-indent: 2em;">Doug Lea 这样评价它：<br /><blockquote>TransferQueue是一个聪明的队列，它是ConcurrentLinkedQueue, SynchronousQueue (在公平模式下), 无界的LinkedBlockingQueues等的超集。</blockquote>显然易见，混合了若干高级特性，并且具有高性能的一个组合体，一个多面手。</div><div style="text-indent: 2em;">这里有一个有关LinkedTransferQueue的Doug Lea等人所撰写论文，讨论了其算法、性能等，地址：http://www.cs.rice.edu/~wns1/papers/2006-PPoPP-SQ.pdf</div><div style="text-indent: 2em;">单纯从队列来看，TransferQueue接口增加了一些很实用的新特性，其transfer方法提供了线程之间直接交换对象的捷径，下面一一说来。</div><div style="text-indent: 2em;"><ol><li>transfer(E e)<br />若当前存在一个正在等待获取的消费者线程，即立刻移交之；否则，会插入当前元素e到队列尾部，并且等待进入阻塞状态，到有消费者线程取走该元素。<span class="Apple-tab-span" style="white-space: pre;"> </span></li><li>tryTransfer(E e)<br />若当前存在一个正在等待获取的消费者线程（使用take()或者poll()函数），使用该方法会即刻转移/传输对象元素e；<br />若不存在，则返回false，并且不进入队列。<br />这是一个不阻塞的操作。</li><li>tryTransfer(E e, long timeout, TimeUnit unit)<br />若当前存在一个正在等待获取的消费者线程，会立即传输给它;<br />否则将插入元素e到队列尾部，并且等待被消费者线程获取消费掉,<br />若在指定的时间内元素e无法被消费者线程获取，则返回false，同时该元素被移除。</li><li>hasWaitingConsumer()<br />很明显，判断是否终端消费者线程</li><li>getWaitingConsumerCount()<br />字面意思很明白，获取终端所有等待获取元素的消费线程数量</li><li>size()<br />因为队列的异步特性，检测当前队列的元素个数需要逐一迭代，可能会得到一个不太准确的结果，尤其是在遍历时有可能队列发生更改。</li><li>批量操作<br />类似于&nbsp;addAll，removeAll, retainAll, containsAll, equals, toArray 等方法，API不能保证一定会立刻执行。<br />因此，我们在使用过程中，不能有所期待，这是一个具有异步特性的队列。</li></ol></div><br /><div style="text-indent: 2em;"><strong>注意事项：</strong><br /><ul><li>无论是transfer还是tryTransfer方法，在&gt;=1个消费者线程等待获取元素时（此时队列为空），都会立刻转交，这属于线程之间的元素交换。注意，这时，元素并没有进入队列。</li><li>在队列中已有数据情况下，transfer将需要等待前面数据被消费掉，直到传递的元素e被消费线程取走为止。</li><li>使用transfer方法，工作者线程可能会被阻塞到生产的元素被消费掉为止</li><li>消费者线程等待为零的情况下，各自的处理元素入队与否情况有所不同。</li><li>size()方法，需要迭代，可能不太准确，尽量不要调用。</li></ul></div><br /><div style="text-indent: 2em;">或许，下次我们在构造一个线程池时，可以考虑使用TransferQueue：<br /><pre>public static ExecutorService newTransferCachedThreadPool() {<br />        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,<br />                                      60L, TimeUnit.SECONDS,<br />                                      new LinkedTransferQueue<runnable>());<br />    }<br /><br /></runnable></pre></div><br /><div style="text-indent: 2em;">简单测试代码:</div><script src="https://gist.github.com/1715742.js?file=TestTransferQueue.java"></script><br /><br /><div style="text-indent: 2em;">参考资料:<br /><br /><ol><li><a href="http://tech.puredanger.com/2009/02/28/java-7-transferqueue" target="_blank">Java 7 TransferQueue</a></li></ol></div><div style="text-indent: 2em;"></div><img src ="http://www.blogjava.net/yongboy/aggbug/369575.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2012-02-04 11:28 <a href="http://www.blogjava.net/yongboy/archive/2012/02/04/369575.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Fork/Join模式(JSR166y)手记之JVAA6搭建环境,开始学习</title><link>http://www.blogjava.net/yongboy/archive/2012/02/03/369576.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Fri, 03 Feb 2012 15:01:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2012/02/03/369576.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/369576.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2012/02/03/369576.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/369576.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/369576.html</trackback:ping><description><![CDATA[<div style="text-indent: 2em;">Doug Lea的jsr166y，主要体现在Fork/Join模式，分而治之，然后合并结果，这么一种编程模式。相比JDK 1.6内置的JUC并发框架，更加细粒度。虽然已经内置JDK 1.7中，但本文环境基于JDK 1.6，因此在相关包的引用方面，差异在于包的路径。</div><div style="text-indent: 2em;">有关Fork/Join的一些摘抄：<br /><blockquote>fork/join框架是一个&#8220;多核友好的、轻量级并行框架 &#8221;，它支持并行编程风格，将问题递归拆分成多个更小片断，以并行和调配的方式解决。Fork-join融合了分而治之技术；获取问题后，递归地将它分成多个子问题，直到每个子问题都足够小，以至于可以高效地串行地解决它们。递归的过程将会把问题分成两个或者多个子问题，然后把这些问题放入队列中等待处理（fork步骤），接下来等待所有子问题的结果（join步骤），把多个结果合并到一起。</blockquote>Doug Lea描述了fork/join框架最可能的使用场景和采用过程：<br /><blockquote>总之，我期望其使用曲线与其他并发工具雷同。最初，只有较少真正需要的人使用它们，但最终很难找到不依赖于它们的程序，它们常常深埋在底层基础架构组件中。因此，表面语法支持可能并不是那么重要&#8212;&#8212;类库/组件开发者越是想合并它们，其用法越是表现的笨拙。<br />理想的情况下，有几个使用层次：<br />1. &#8220;并行做事&#8221;层次，语言或工具翻译成并行代码，同时检查安全性/活跃性。这仍部分处于研究领域。<br /><br />2. 安排集合的并行操作。&#8212;&#8212;map、reduce、apply等等。那些想使用一次性操作特性操纵集合的程序员们，可以使用这些特性来提高常用处理类型的速度。（这是ListTasks、ArrayTasks等等层次）<br /><br />3. 手工生效forkjoin以解决特定问题。这是我正在全力投入的层次，以确保我们可能使用工作窃取框架来支持范围广泛的并行算法。（当前一些怪模怪样的和缺乏解释的方法，如isQuiescent是为这种高级用法设计的。多数程序只使用&#8220;fork&#8221;和&#8220;join&#8221;，但当你需要其他这些方法时，它们也被提供了。）<br /><br />4. 扩展框架以创建新类型的ForkJoinTasks等等。例如，那些需要事务的操作。只有很少量的人（例如，或许是Fortress运行时类库开发者）需要这么做，但是需要有足够的基础扩展钩子来才能做好。</blockquote>本文开始学习，按照心得步骤一步一步进行学习。即将开始。</div><div style="text-indent: 2em;">Doug Lea有关JUC的官网地址：http://gee.cs.oswego.edu/dl/concurrency-interest/<br /><ol><li>下载原始代码（<a href="http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/cvs-root.tar.gz?parent=1&amp;view=tar">http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/cvs-root.tar.gz?parent=1&amp;view=tar</a>）到本地</li><li>把cvs-root.tar.gz解压到本地某个目录，假设解压地址是d:\workspace\jsr166</li><li>进入CMD命令行，切换到d:\workspace\jsr166目录下</li><li>运行ANT命令：ant jsr166ydist （没设置ANT环境，自行处理）</li><li>在dist目录生成jsr166y.jar文件、docs目录</li></ol></div><div style="text-indent: 2em;">在相关项目中加入jsr166y.jar依赖即可。<br />必备条件：JDK 1.6 </div><div style="text-indent: 2em;">机器配置：<br /><blockquote>操作系统 Windows XP 专业版 32位 SP3<br />处理器  英特尔 Pentium(奔腾) P6200 @ 2.13GHz<br />内存  4 GB ( 金士顿 DDR3 1333MHz / 三星 DDR3 1333MHz )</blockquote></div><div style="text-indent: 2em;">参考资料:<br /><ol><li><a href="http://www.infoq.com/cn/news/2008/03/fork_join" target="_blank">Java 7的并行支持：Fork/Join</a></li><li><a href="http://www.infoq.com/cn/news/2007/07/concurrency-java-se-7" target="_blank">Java SE 7的新并发特性</a></li><li><a href="http://www.infoq.com/cn/news/2011/08/messinger-vava7-qanda" target="_blank">Adam Messinger谈Java 7与8</a></li></ol></div><div style="text-indent: 2em;"></div><img src ="http://www.blogjava.net/yongboy/aggbug/369576.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2012-02-03 23:01 <a href="http://www.blogjava.net/yongboy/archive/2012/02/03/369576.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Servlet 3.0笔记之文件下载的那点事情</title><link>http://www.blogjava.net/yongboy/archive/2012/01/19/369577.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Thu, 19 Jan 2012 02:21:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2012/01/19/369577.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/369577.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2012/01/19/369577.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/369577.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/369577.html</trackback:ping><description><![CDATA[<div style="text-indent: 2em;">使用Servlet 3.0 提供文件下载，当然了任何Servlet版本，都可以做到，这里仅仅作为知识的积累。下面贴出代码，防止忘却。</div><div style="text-indent: 2em;"><h3>   一。常规方式文件下载示范</h3></div><script src="https://gist.github.com/1631875.js?file=DownloadFileAction.java"></script><br /><div style="text-indent: 2em;">很普通，简单易用，不多说。一般情况下，够用了。</div><h3>   二。伪零拷贝(zero copy)方式文件下载示范</h3><div style="text-indent: 2em;">变化不大，关键代码在于：利用<br /><blockquote>FileChannel.transferTo(long position, long count, WritableByteChannel target)</blockquote>方法达到零拷贝(zero copy)目的。把HttpServletResponse的输出对象(ServletOutputStream)利用Channels.newChannel(OutputStream out)工具，构建一个WritableByteChannel对象而已。</div><blockquote>OutputStream out = response.getOutputStream();<br />WritableByteChannel outChannel = Channels.newChannel(out);</blockquote><div style="text-indent: 2em;">测试代码：</div><script src="https://gist.github.com/1631901.js?file=DownloadFileZeroCopyAction.java"></script><br /><div style="text-indent: 2em;">心存疑虑的是，这个是伪零拷贝方式实现。查看一下Channels.newChannel的源码：<br /><pre class="prettyprint lang-java">public static WritableByteChannel newChannel(final OutputStream out) {<br /> if (out == null) {<br />     throw new NullPointerException();<br /> }<br /><br />        if (out instanceof FileOutputStream &amp;&amp;<br />     FileOutputStream.class.equals(out.getClass())) {<br />                return ((FileOutputStream)out).getChannel();<br />        }<br /><br /> return new WritableByteChannelImpl(out);<br />    }<br /></pre>因为输入的方法参数为ServletOutputStream类型实例，因此只能返回一个新构建的WritableByteChannelImpl对象。具体构建：<br /><pre class="prettyprint lang-java">private static class WritableByteChannelImpl<br />        extends AbstractInterruptibleChannel // Not really interruptible<br />        implements WritableByteChannel<br />    {<br />        OutputStream out;<br />        private static final int TRANSFER_SIZE = 8192;<br />        private byte buf[] = new byte[0];<br />        private boolean open = true;<br />        private Object writeLock = new Object();<br /><br />        WritableByteChannelImpl(OutputStream out) {<br />            this.out = out;<br />        }<br /><br />        public int write(ByteBuffer src) throws IOException {<br />            int len = src.remaining();<br />            int totalWritten = 0;<br />            synchronized (writeLock) {<br />                while (totalWritten &lt; len) {<br />                    int bytesToWrite = Math.min((len - totalWritten),<br />                                                TRANSFER_SIZE);<br />                    if (buf.length &lt; bytesToWrite)<br />                        buf = new byte[bytesToWrite];<br />                    src.get(buf, 0, bytesToWrite);<br />                    try {<br />                        begin();<br />                        out.write(buf, 0, bytesToWrite);<br />                    } finally {<br />                        end(bytesToWrite &gt; 0);<br />                    }<br />      totalWritten += bytesToWrite;<br />                }<br />                return totalWritten;<br />            }<br />        }<br /><br />        protected void implCloseChannel() throws IOException {<br />            out.close();<br />            open = false;<br />        }<br />    }<br /></pre>很显然，也是属于内存类型的拷贝了，只能算作伪零拷贝实现了。</div><div style="text-indent: 2em;"><h3>  三。转发到文件服务器上</h3></div><div style="text-indent: 2em;">一般常识为，让最擅长的人来做最擅长的事情，是为高效。使用类如Nginx高效的Web服务器专门处理文件下载业务，达到零拷贝的目的，也是最佳搭配组合。Nginx可以利用header元数据X-Accel-Redirect来控制文件下载行为，甚是不错。利用JAVA进行业务逻辑判断，若符合规则，则提交给Nginx进行处理文件的下载，否则，返回给终端用户权限不够等信息。</div><div style="text-indent: 2em;">用于控制用户是否具有资格进行文件下载业务的控制器：</div><script src="https://gist.github.com/1632237.js?file=DownloadFileWithNginxAction.java"></script><br /><div style="text-indent: 2em;">当然，这个仅仅用于演示，逻辑简单。因为需要和nginx服务器进行配合，构建一个Server，其配置文件：</div><script src="https://gist.github.com/1632228.js?file=dl_nginx.conf"></script><br /><div style="text-indent: 2em;">我们在nginx配置文件中，设置<strong>/dowloads/</strong>目录是不允许直接访问的，必须经由/download/控制器进行转发方可。经测试，中文名不会出现乱码问题，保存的文件也是我们所请求的文件，同名，也不会出现乱码问题。但是，若在后台获取文件名，用于显示/输出，则需要从ISO-8859-1解码成GBK编码方可。</div><div style="text-indent: 2em;">但这样做，可能被绑定到某个类型的服务器，但也值得。实际上切换到Apache也是很简单的。</div><div style="text-indent: 2em;">PS : Apache服务器诶则对应X-Sendfile头部属性，因很长时间不再使用Apache，这里不再测试。<br /><a href="https://skydrive.live.com/redir.aspx?cid=cf7746837803bc50&amp;resid=CF7746837803BC50%211273&amp;parid=CF7746837803BC50%21546" target="_blank">源码下载</a></div><div style="text-indent: 2em;">参考资料：<br /><ol><li><a href="http://www.ibm.com/developerworks/cn/java/j-zerocopy/" target="_blank">通过零拷贝实现有效数据传输</a></li><li><br /><a class="question-hyperlink" href="http://stackoverflow.com/questions/4645441/most-effective-way-to-write-file-to-servletoutputstream">Most effective way to write File to ServletOutputStream</a></li><li><a href="http://stackoverflow.com/questions/1605332/java-nio-filechannel-versus-fileoutputstream-performance-usefulness">Java NIO FileChannel versus FileOutputstream performance / usefulness</a></li><li><a href="http://wiki.nginx.org/NginxChsXSendfile">NginxChsXSendfile</a></li></ol></div><img src ="http://www.blogjava.net/yongboy/aggbug/369577.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2012-01-19 10:21 <a href="http://www.blogjava.net/yongboy/archive/2012/01/19/369577.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Servlet 3.0笔记之Servlet的异步特性支持失效怎么办？</title><link>http://www.blogjava.net/yongboy/archive/2012/01/18/369578.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Wed, 18 Jan 2012 02:32:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2012/01/18/369578.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/369578.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2012/01/18/369578.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/369578.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/369578.html</trackback:ping><description><![CDATA[<div style="text-indent: 2em;">满心欢喜的为Servlet 添加上异步支持注解（asyncSupported = true），不曾想，其异步特性完全不起作用，仔细检测项目，发现存在一个编码拦截器（Filter），虽使用注解，但未标明支持异步，导致被拦截的标注为异步支持的Servlet，异步特性皆失效。怎么办，在Filter中注解里面添加asyncSupported = true。问题解决。</div><div style="text-indent: 2em;">但转念一想，因历史原因，遗留系统会存在很多的Servlet 2.*规范的Filter，无法支持异步，怎么办？全部手动修改为注解版本，可能不太现实。还好，Doug Lea的JUC并发包，为我们提供了一种实现思路。 </div><div style="text-indent: 2em;">实际步骤:<br /><ol><li>准备一个线程池 </li><li>把当前请求相关属性包装进一个任务线程中</li><li>获取当前任务线程执行结果（不一定会有返回值） </li><li>阻塞，执行完毕或超时，或被中断异常，可以输出客户端</li><li>整个请求结束 </li></ol></div><div style="text-indent: 2em;">实际上，提交到一个线程池的任务线程，默认会返回一个Future对象，利用Future对象的get方法阻塞的特性，当前请求需要等待任务线程执行的结束，若指定时间内任务线程顺利完成，则不必等到设定的时间的边界即可自然往下执行。</div><div style="text-indent: 2em;">实际代码：</div><script src="https://gist.github.com/1625881.js?file=DemoAsync3Action.java"></script><br /><div style="text-indent: 2em;">需要备注说明的是，若Future.get()无参数，则意味着需要等待计算完成，然后获取其结果。这样可不用设定等待时间了。更多信息，请参考JDK。</div><div style="text-indent: 2em;"><a href="https://skydrive.live.com/redir.aspx?cid=cf7746837803bc50&amp;resid=CF7746837803BC50%211272&amp;parid=CF7746837803BC50%21546" target="_blank">测试代码下载</a></div><img src ="http://www.blogjava.net/yongboy/aggbug/369578.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2012-01-18 10:32 <a href="http://www.blogjava.net/yongboy/archive/2012/01/18/369578.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA方法值传递OR引用传递，不过是浮云~</title><link>http://www.blogjava.net/yongboy/archive/2010/11/25/346214.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Thu, 25 Nov 2010 13:36:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2010/11/25/346214.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/346214.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2010/11/25/346214.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/346214.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/346214.html</trackback:ping><description><![CDATA[<p>对于JAVA方法是值传递，还是引用传递，有人一直以来争论不休。不如忘记这些提法，反而会容易理解一些。</p> <p>参数的传递分为两类：</p> <p>1。基本数据，变量是直接赋值。</p> <div><pre>	<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> main(String[] args) {<br />		<span style="color: #0000ff">int</span> <span style="color: #0000ff">value</span> = 0;<br />		change(<span style="color: #0000ff">value</span>);<br />		System.<span style="color: #0000ff">out</span>.println(<span style="color: #0000ff">value</span>);<br />	}<br /><br />	<span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> change(<span style="color: #0000ff">int</span> num) {<br />		num = 99;<br />	}</pre></div><br /><p><br />输出结果为：0</p><br /><p>可以这么认为，在栈区 value 的值赋给了一个生命周期很短的变量 num，下面的事情就是变量num的自家事情了。<br /></p><br /><p>2。对象参数，传递的是永远是对象的引用。</p><br /><div><pre><span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> ObjectTest {<br /><br />	<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> main(String[] args) {<br />		Person p = <span style="color: #0000ff">new</span> Person("<span style="color: #8b0000">Hi</span>");<br /><br />		change(p);<br />		System.out.println(p);<br />	}<br /><br />	<span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> change(Person per) {<br />		per.setName("<span style="color: #8b0000">China</span>");<br />		<br />		per = <span style="color: #0000ff">new</span> Person("<span style="color: #8b0000">english</span>");<br />	}<br />}<br /><br /><span style="color: #0000ff">class</span> Person {<br />	<span style="color: #0000ff">public</span> Person(String name) {<br />		<span style="color: #0000ff">this</span>.name = name;<br />	}<br /><br />	<span style="color: #0000ff">private</span> String name;<br /><br />	<span style="color: #0000ff">public</span> String getName() {<br />		<span style="color: #0000ff">return</span> name;<br />	}<br /><br />	<span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> setName(String name) {<br />		<span style="color: #0000ff">this</span>.name = name;<br />	}<br /><br />	@Override<br />	<span style="color: #0000ff">public</span> String toString() {<br />		<span style="color: #0000ff">return</span> "<span style="color: #8b0000">name : </span>" + getName();<br />	}<br />}</pre></div>这个例子最后输出结果为：<strong>name ：china</strong><br /><p>在栈区（stack），存在两个Person对象引用：|<br />p把对象的引用地址赋值给了per，p也就完成了使命；</p><br /><p>per.setName("<span style="color: #8b0000">China</span>"); 这一句话意味着per操纵目标对象的setName方法。此时p和per都指向了同一个存放在堆区(heap)Person对象；</p><br /><p>per所引用的对象地址被重新赋值：per = <span style="color: #0000ff">new</span> Person("<span style="color: #8b0000">english</span>"); 自此per就和p就一点关系都没有了：p所指向的对象和per所指向的对象是两个不同的对象了。</p><br /><p>常见的基本数据数组也是一种对象。</p><br /><p>小结：无论是基本数据还是对象，都是赋值操作，基本数据赋值直接在栈区进行，对象只是把对象的引用地址赋值，但对应同一个对象。</p><br /><p>有时间会把图形附上，这样理解起来会更形象一些。</p><img src ="http://www.blogjava.net/yongboy/aggbug/346214.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2010-11-25 21:36 <a href="http://www.blogjava.net/yongboy/archive/2010/11/25/346214.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>分享一个免费的UML设计工具，精简版本的NetBeans 6.5</title><link>http://www.blogjava.net/yongboy/archive/2010/10/27/346215.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Wed, 27 Oct 2010 07:02:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2010/10/27/346215.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/346215.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2010/10/27/346215.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/346215.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/346215.html</trackback:ping><description><![CDATA[<p>一直在寻找一个比较好使的UML设计工具，尝试了若干，感觉还是NetBeans提供的UML工具不错，支持UML 2.0。至于Eclipse上面的UML插件，也有尝试，一一放弃了。</p>  <p>NetBeans 6.5对UML插件支持好一些，遂而去除里面很少使用到的插件，只是保留了如下几个插件：</p>  <div><a href="http://lh6.ggpht.com/_iP4ZGnOhL6U/TMfOOA2KWgI/AAAAAAAAAu8/NQJq-f9081k/s1600-h/image%5B4%5D.png"><img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" alt="image" src="http://lh3.ggpht.com/_iP4ZGnOhL6U/TMfOP-W0gnI/AAAAAAAAAvA/fbtLye-1s9A/image_thumb%5B2%5D.png?imgmax=800" border="0" height="367" width="573" /></a> </div>  <p>&nbsp;</p>  <p>这样只能新建java和uml项目了，启动速度快了。</p>  <p><a href="http://lh5.ggpht.com/_iP4ZGnOhL6U/TMfORCbJndI/AAAAAAAAAvE/t9PMlRWYUlI/s1600-h/image%5B10%5D.png"><img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" alt="image" src="http://lh4.ggpht.com/_iP4ZGnOhL6U/TMfOSWB_TkI/AAAAAAAAAvI/vYobGhG0Pyw/image_thumb%5B6%5D.png?imgmax=800" border="0" height="420" width="606" /></a> </p>  <p>有一点很赞的，可以把某个设计模式的UML类图直接调出来，在空白类图上点击右键，选择&#8220;应用设计模式&#8221;：</p>  <p><a href="http://lh3.ggpht.com/_iP4ZGnOhL6U/TMfOTsZ9_fI/AAAAAAAAAvM/fOB3VXtjFyY/s1600-h/image%5B14%5D.png"><img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" alt="image" src="http://lh3.ggpht.com/_iP4ZGnOhL6U/TMfOUpLtslI/AAAAAAAAAvQ/D7crwWhXiNw/image_thumb%5B8%5D.png?imgmax=800" border="0" height="314" width="349" /></a>&nbsp;</p>  <p>在下面的步骤中，选择相应的模式即可：</p>  <p><a href="http://lh6.ggpht.com/_iP4ZGnOhL6U/TMfOWDEiciI/AAAAAAAAAvU/4D7NUL48tl0/s1600-h/image%5B19%5D.png"><img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" alt="image" src="http://lh3.ggpht.com/_iP4ZGnOhL6U/TMfOX51M6SI/AAAAAAAAAvY/tJCRYQU_Y8I/image_thumb%5B11%5D.png?imgmax=800" border="0" height="456" width="552" /></a> </p>  <p>下面就是责任链模式对应的UML图：</p>  <p><a href="http://lh3.ggpht.com/_iP4ZGnOhL6U/TMfOZPhXpYI/AAAAAAAAAvc/CjiCsfWsdNc/s1600-h/image%5B23%5D.png"><img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" alt="image" src="http://lh3.ggpht.com/_iP4ZGnOhL6U/TMfOah6F1rI/AAAAAAAAAvg/DFd8Kc210Es/image_thumb%5B13%5D.png?imgmax=800" border="0" height="408" width="403" /></a>&nbsp;</p>  <p>打包下载地址：</p>  <p><a href="http://cid-cf7746837803bc50.office.live.com/self.aspx/public/IDE/NetBeans%206.5-lite.7z" target="_blank">下载</a> </p>  <p>７Ｚ格式，45.9 MB大小，解压后即可使用。</p><img src ="http://www.blogjava.net/yongboy/aggbug/346215.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2010-10-27 15:02 <a href="http://www.blogjava.net/yongboy/archive/2010/10/27/346215.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>建造者模式：导向器封装生成产品的具体步骤</title><link>http://www.blogjava.net/yongboy/archive/2010/10/26/346216.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Tue, 26 Oct 2010 09:36:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2010/10/26/346216.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/346216.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2010/10/26/346216.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/346216.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/346216.html</trackback:ping><description><![CDATA[《设计模式》中定义：   <br /><strong>Builder模式的缘起：</strong>   <br />&nbsp;&nbsp;&nbsp; 假设创建游戏中的一个房屋House设施，该房屋的构建由几部分组成，且各个部分富于变化。如果使用最直观的设计方法，每一个房屋部分的变化，都将导致房屋构建的重新修正.....   <br /><strong>动机（Motivation):</strong>   <br />&nbsp;&nbsp;&nbsp; 在软件系统中，有时候面临一个"复杂对象"的创建工作，其通常由各个部分的子对象用一定算法构成;由于需求的变化，这个复杂对象的各个部分经常面临着剧烈的变化，但是将它们组合到一起的算法却相对稳定。   <br />&nbsp;&nbsp;&nbsp; 如何应对种变化呢？如何提供一种"封装机制"来隔离出"复杂对象的各个部分"的变化，从而保持系统中的"稳定构建算法"不随需求的改变而改变？   <br /><strong>意图(Intent)：</strong>   <br />&nbsp;&nbsp;&nbsp; 将一个复杂对象的构建与其表示相分离，使得同样的构建过程可以创建不同的表示。   <br /><div class="separator" style="clear: both; text-align: center;"></div>UML 表示如下：   <br /><table class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;" align="center" cellpadding="0" cellspacing="0"><tbody><tr>       <td style="text-align: center;"><a href="http://lh5.ggpht.com/_iP4ZGnOhL6U/TM4k3-oHc-I/AAAAAAAAAwA/FDi_ksHtMUs/s1600-h/uml2%5B3%5D.png"><img alt="uml2" src="http://lh6.ggpht.com/_iP4ZGnOhL6U/TM4k5AKz_JI/AAAAAAAAAwE/KNAqS_iyHk0/uml2_thumb%5B1%5D.png?imgmax=800" style="border-bottom-color: initial; border-bottom-style: initial; border-bottom-width: 0px; border-left-color: initial; border-left-style: initial; border-left-width: 0px; border-right-color: initial; border-right-style: initial; border-right-width: 0px; border-top-color: initial; border-top-style: initial; border-top-width: 0px; display: inline;" title="uml2" border="0" height="786" width="773" /></a>   </td>     </tr><tr>       <td class="tr-caption" style="text-align: center;">Builder模式</td>     </tr></tbody></table><br />这里的Builder是一个抽象类，不是接口，为了共用一些属性和代码，把稍微变化的部分让子类来实现（显然Builder 和 ConcreteOneProduct、ConcreteTwoProduct组成了个模板模式）。   <br /><br />先看建造者,一个抽象类，提供一些公用实现(Builder.java)：   <br /><div class="java" align="left"><table bgcolor="#ffffff" border="0" cellpadding="3" cellspacing="0">   <tbody><tr>     <td align="left" nowrap="nowrap" valign="top"><code><span style="color: #3f5fbf;">/**</span><br /><span style="color: white;">&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;一个抽象来来替代接口</span><br /><span style="color: white;">&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;</span><br /><span style="color: white;">&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;</span><span style="color: #7f9fbf;">@author&nbsp;</span><span style="color: #3f5fbf;">yongboy@gmail.com</span><br /><span style="color: white;">&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;@date&nbsp;2010-10-26</span><br /><span style="color: white;">&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;</span><span style="color: #7f9fbf;">@version&nbsp;</span><span style="color: #3f5fbf;">1.0</span><br /><span style="color: white;">&nbsp;</span><span style="color: #3f5fbf;">*/</span><br /><span style="color: #7f0055;"><strong>public&nbsp;abstract&nbsp;class&nbsp;</strong></span><span style="color: black;">Builder&nbsp;</span><span style="color: black;">{</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>protected&nbsp;</strong></span><span style="color: black;">Product&nbsp;product&nbsp;=&nbsp;</span><span style="color: #7f0055;"><strong>null</strong></span><span style="color: black;">;</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>public&nbsp;</strong></span><span style="color: black;">Builder</span><span style="color: black;">()&nbsp;{</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">product&nbsp;=&nbsp;</span><span style="color: #7f0055;"><strong>new&nbsp;</strong></span><span style="color: black;">Product</span><span style="color: black;">()</span><span style="color: black;">;</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: black;">}</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #3f5fbf;">/**</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;产生描述内容</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;</span><span style="color: #3f5fbf;">*/</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>public&nbsp;abstract&nbsp;</strong></span><span style="color: #7f0055;"><strong>void&nbsp;</strong></span><span style="color: black;">genDesc</span><span style="color: black;">(</span><span style="color: black;">String&nbsp;desc</span><span style="color: black;">)</span><span style="color: black;">;</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #3f5fbf;">/**</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;绘制三角形</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;</span><span style="color: #3f5fbf;">*/</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>public&nbsp;abstract&nbsp;</strong></span><span style="color: #7f0055;"><strong>void&nbsp;</strong></span><span style="color: black;">genTriangle</span><span style="color: black;">(</span><span style="color: #7f0055;"><strong>int&nbsp;</strong></span><span style="color: black;">len</span><span style="color: black;">)</span><span style="color: black;">;</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #3f5fbf;">/**</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;输出最终产生的产品</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;</span><span style="color: #7f9fbf;">@return</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;</span><span style="color: #3f5fbf;">*/</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>public&nbsp;</strong></span><span style="color: black;">Product&nbsp;getProduct</span><span style="color: black;">()&nbsp;{</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>return&nbsp;</strong></span><span style="color: black;">product;</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: black;">}</span><br /><span style="color: black;">}</span></code>       </td>     </tr></tbody></table></div><br />一个实现，主要是绘制三角形： <br /><div class="java" align="left"><table bgcolor="#ffffff" border="0" cellpadding="3" cellspacing="0">   <tbody><tr>     <td align="left" nowrap="nowrap" valign="top"><code><span style="color: #7f0055;"><strong>public&nbsp;class&nbsp;</strong></span><span style="color: black;">ConcreteOneBuilder&nbsp;</span><span style="color: #7f0055;"><strong>extends&nbsp;</strong></span><span style="color: black;">Builder&nbsp;</span><span style="color: black;">{</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #646464;">@Override</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>public&nbsp;</strong></span><span style="color: #7f0055;"><strong>void&nbsp;</strong></span><span style="color: black;">genDesc</span><span style="color: black;">(</span><span style="color: black;">String&nbsp;desc</span><span style="color: black;">)&nbsp;{</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">product.setDesc</span><span style="color: black;">(</span><span style="color: black;">desc</span><span style="color: black;">)</span><span style="color: black;">;</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: black;">}</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #646464;">@Override</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>public&nbsp;</strong></span><span style="color: #7f0055;"><strong>void&nbsp;</strong></span><span style="color: black;">genTriangle</span><span style="color: black;">(</span><span style="color: #7f0055;"><strong>int&nbsp;</strong></span><span style="color: black;">len</span><span style="color: black;">)&nbsp;{</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">StringBuilder&nbsp;sb&nbsp;=&nbsp;</span><span style="color: #7f0055;"><strong>new&nbsp;</strong></span><span style="color: black;">StringBuilder</span><span style="color: black;">()</span><span style="color: black;">;</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>for&nbsp;</strong></span><span style="color: black;">(</span><span style="color: #7f0055;"><strong>int&nbsp;</strong></span><span style="color: black;">i&nbsp;=&nbsp;</span><span style="color: #990000;">1</span><span style="color: black;">;&nbsp;i&nbsp;&lt;&nbsp;len;&nbsp;i++</span><span style="color: black;">)&nbsp;{</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>for&nbsp;</strong></span><span style="color: black;">(</span><span style="color: #7f0055;"><strong>int&nbsp;</strong></span><span style="color: black;">j&nbsp;=&nbsp;</span><span style="color: #990000;">0</span><span style="color: black;">;&nbsp;j&nbsp;&lt;&nbsp;i;&nbsp;j++</span><span style="color: black;">)&nbsp;{</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">sb.append</span><span style="color: black;">(</span><span style="color: #2a00ff;">"&nbsp;*"</span><span style="color: black;">)</span><span style="color: black;">;</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">}</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">sb.append</span><span style="color: black;">(</span><span style="color: #2a00ff;">"\n"</span><span style="color: black;">)</span><span style="color: black;">;</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">}</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">product.setContent</span><span style="color: black;">(</span><span style="color: black;">sb.toString</span><span style="color: black;">())</span><span style="color: black;">;</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: black;">}</span><br /><span style="color: black;">}</span></code>       </td>     </tr></tbody></table></div><br />第二个实现： <br /><div class="java" align="left"><table bgcolor="#ffffff" border="0" cellpadding="3" cellspacing="0">   <tbody><tr>     <td align="left" nowrap="nowrap" valign="top"><code><span style="color: #7f0055;"><strong>public&nbsp;class&nbsp;</strong></span><span style="color: black;">ConcreteTwoBuilder&nbsp;</span><span style="color: #7f0055;"><strong>extends&nbsp;</strong></span><span style="color: black;">Builder&nbsp;</span><span style="color: black;">{</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #646464;">@Override</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>public&nbsp;</strong></span><span style="color: #7f0055;"><strong>void&nbsp;</strong></span><span style="color: black;">genDesc</span><span style="color: black;">(</span><span style="color: black;">String&nbsp;desc</span><span style="color: black;">)&nbsp;{</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">product.setDesc</span><span style="color: black;">(</span><span style="color: black;">desc</span><span style="color: black;">)</span><span style="color: black;">;</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: black;">}</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #646464;">@Override</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>public&nbsp;</strong></span><span style="color: #7f0055;"><strong>void&nbsp;</strong></span><span style="color: black;">genTriangle</span><span style="color: black;">(</span><span style="color: #7f0055;"><strong>int&nbsp;</strong></span><span style="color: black;">len</span><span style="color: black;">)&nbsp;{</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">StringBuilder&nbsp;sb&nbsp;=&nbsp;</span><span style="color: #7f0055;"><strong>new&nbsp;</strong></span><span style="color: black;">StringBuilder</span><span style="color: black;">()</span><span style="color: black;">;</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>for&nbsp;</strong></span><span style="color: black;">(</span><span style="color: #7f0055;"><strong>int&nbsp;</strong></span><span style="color: black;">i&nbsp;=&nbsp;len;&nbsp;i&nbsp;&gt;&nbsp;</span><span style="color: #990000;">0</span><span style="color: black;">;&nbsp;i--</span><span style="color: black;">)&nbsp;{</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>int&nbsp;</strong></span><span style="color: black;">spaceNum&nbsp;=&nbsp;len&nbsp;-&nbsp;i;</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>for&nbsp;</strong></span><span style="color: black;">(</span><span style="color: #7f0055;"><strong>int&nbsp;</strong></span><span style="color: black;">j&nbsp;=&nbsp;</span><span style="color: #990000;">0</span><span style="color: black;">;&nbsp;j&nbsp;&lt;&nbsp;spaceNum;&nbsp;j++</span><span style="color: black;">)&nbsp;{</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">sb.append</span><span style="color: black;">(</span><span style="color: #2a00ff;">"&nbsp;&nbsp;"</span><span style="color: black;">)</span><span style="color: black;">;</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">}</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>for&nbsp;</strong></span><span style="color: black;">(</span><span style="color: #7f0055;"><strong>int&nbsp;</strong></span><span style="color: black;">j&nbsp;=&nbsp;</span><span style="color: #990000;">0</span><span style="color: black;">;&nbsp;j&nbsp;&lt;&nbsp;i;&nbsp;j++</span><span style="color: black;">)&nbsp;{</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">sb.append</span><span style="color: black;">(</span><span style="color: #2a00ff;">"&nbsp;*"</span><span style="color: black;">)</span><span style="color: black;">;</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">}</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">sb.append</span><span style="color: black;">(</span><span style="color: #2a00ff;">"\n"</span><span style="color: black;">)</span><span style="color: black;">;</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">}</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">product.setContent</span><span style="color: black;">(</span><span style="color: black;">sb.toString</span><span style="color: black;">())</span><span style="color: black;">;</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: black;">}</span><br /><span style="color: black;">}</span></code>       </td>     </tr></tbody></table></div><br />产品定义: <br /><div class="java" align="left"><table bgcolor="#ffffff" border="0" cellpadding="3" cellspacing="0">   <tbody><tr>     <td align="left" nowrap="nowrap" valign="top"><code><span style="color: #3f5fbf;">/**</span><br /><span style="color: white;">&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;一个有关三角的产品</span><br /><span style="color: white;">&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;</span><br /><span style="color: white;">&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;</span><span style="color: #7f9fbf;">@author&nbsp;</span><span style="color: #3f5fbf;">yongboy@gmail.com</span><br /><span style="color: white;">&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;@date&nbsp;2010-10-26</span><br /><span style="color: white;">&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;</span><span style="color: #7f9fbf;">@version&nbsp;</span><span style="color: #3f5fbf;">1.0</span><br /><span style="color: white;">&nbsp;</span><span style="color: #3f5fbf;">*/</span><br /><span style="color: #7f0055;"><strong>public&nbsp;class&nbsp;</strong></span><span style="color: black;">Product&nbsp;</span><span style="color: #7f0055;"><strong>implements&nbsp;</strong></span><span style="color: black;">Serializable&nbsp;</span><span style="color: black;">{</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>private&nbsp;final&nbsp;static&nbsp;</strong></span><span style="color: #7f0055;"><strong>long&nbsp;</strong></span><span style="color: black;">serialVersionUID&nbsp;=&nbsp;</span><span style="color: #990000;">23536326475869L</span><span style="color: black;">;</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #3f5fbf;">/**</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;当前产品的描述</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;</span><span style="color: #3f5fbf;">*/</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>private&nbsp;</strong></span><span style="color: black;">String&nbsp;desc;</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #3f5fbf;">/**</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;当前产品的详细内容</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;</span><span style="color: #3f5fbf;">*/</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>private&nbsp;</strong></span><span style="color: black;">String&nbsp;content;</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>public&nbsp;</strong></span><span style="color: black;">Product</span><span style="color: black;">()&nbsp;{</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: black;">}</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>public&nbsp;</strong></span><span style="color: black;">String&nbsp;getDesc</span><span style="color: black;">()&nbsp;{</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>return&nbsp;</strong></span><span style="color: black;">desc;</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: black;">}</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>public&nbsp;</strong></span><span style="color: #7f0055;"><strong>void&nbsp;</strong></span><span style="color: black;">setDesc</span><span style="color: black;">(</span><span style="color: black;">String&nbsp;desc</span><span style="color: black;">)&nbsp;{</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>this</strong></span><span style="color: black;">.desc&nbsp;=&nbsp;desc;</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: black;">}</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>public&nbsp;</strong></span><span style="color: black;">String&nbsp;getContent</span><span style="color: black;">()&nbsp;{</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>return&nbsp;</strong></span><span style="color: black;">content;</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: black;">}</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>public&nbsp;</strong></span><span style="color: #7f0055;"><strong>void&nbsp;</strong></span><span style="color: black;">setContent</span><span style="color: black;">(</span><span style="color: black;">String&nbsp;content</span><span style="color: black;">)&nbsp;{</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>this</strong></span><span style="color: black;">.content&nbsp;=&nbsp;content;</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: black;">}</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>public&nbsp;</strong></span><span style="color: black;">String&nbsp;toString</span><span style="color: black;">()&nbsp;{</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>return&nbsp;</strong></span><span style="color: black;">desc&nbsp;+&nbsp;</span><span style="color: #2a00ff;">"\n"&nbsp;</span><span style="color: black;">+&nbsp;content;</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: black;">}</span><br /><span style="color: black;">}</span></code>       </td>     </tr></tbody></table></div><br />导向器,封装着产品生成的具体过程： <br /><div class="java" align="left"><table bgcolor="#ffffff" border="0" cellpadding="3" cellspacing="0">   <tbody><tr>     <td align="left" nowrap="nowrap" valign="top"><code><span style="color: #3f5fbf;">/**</span><br /><span style="color: white;">&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;导向器，封装产品生生成过程</span><br /><span style="color: white;">&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;</span><br /><span style="color: white;">&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;</span><span style="color: #7f9fbf;">@author&nbsp;</span><span style="color: #3f5fbf;">yongboy@gmail.com</span><br /><span style="color: white;">&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;@date&nbsp;2010-10-26</span><br /><span style="color: white;">&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;</span><span style="color: #7f9fbf;">@version&nbsp;</span><span style="color: #3f5fbf;">1.0</span><br /><span style="color: white;">&nbsp;</span><span style="color: #3f5fbf;">*/</span><br /><span style="color: #7f0055;"><strong>public&nbsp;class&nbsp;</strong></span><span style="color: black;">Director&nbsp;</span><span style="color: black;">{</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>private&nbsp;</strong></span><span style="color: black;">Builder&nbsp;builder;</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>private&nbsp;</strong></span><span style="color: #7f0055;"><strong>int&nbsp;</strong></span><span style="color: black;">MAX&nbsp;=&nbsp;</span><span style="color: #990000;">25</span><span style="color: black;">;</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>private&nbsp;</strong></span><span style="color: #7f0055;"><strong>int&nbsp;</strong></span><span style="color: black;">MIN&nbsp;=&nbsp;</span><span style="color: #990000;">10</span><span style="color: black;">;</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>public&nbsp;</strong></span><span style="color: black;">Director</span><span style="color: black;">(</span><span style="color: black;">Builder&nbsp;builder</span><span style="color: black;">)&nbsp;{</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>this</strong></span><span style="color: black;">.builder&nbsp;=&nbsp;builder;</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: black;">}</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>public&nbsp;</strong></span><span style="color: #7f0055;"><strong>void&nbsp;</strong></span><span style="color: black;">construct</span><span style="color: black;">()&nbsp;{</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>int&nbsp;</strong></span><span style="color: black;">len&nbsp;=&nbsp;getNext</span><span style="color: black;">()</span><span style="color: black;">;</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">builder.genDesc</span><span style="color: black;">(</span><span style="color: #2a00ff;">"产品型号("&nbsp;</span><span style="color: black;">+&nbsp;getFormatNum</span><span style="color: black;">(</span><span style="color: black;">len</span><span style="color: black;">)&nbsp;</span><span style="color: black;">+&nbsp;</span><span style="color: #2a00ff;">")："</span><span style="color: black;">)</span><span style="color: black;">;</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">builder.genTriangle</span><span style="color: black;">(</span><span style="color: black;">len</span><span style="color: black;">)</span><span style="color: black;">;</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: black;">}</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>private&nbsp;</strong></span><span style="color: #7f0055;"><strong>int&nbsp;</strong></span><span style="color: black;">getNext</span><span style="color: black;">()&nbsp;{</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>return&nbsp;</strong></span><span style="color: black;">getRandomNum</span><span style="color: black;">(</span><span style="color: black;">MIN,&nbsp;MAX</span><span style="color: black;">)</span><span style="color: black;">;</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: black;">}</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>private&nbsp;static&nbsp;</strong></span><span style="color: black;">String&nbsp;getFormatNum</span><span style="color: black;">(</span><span style="color: #7f0055;"><strong>int&nbsp;</strong></span><span style="color: black;">num</span><span style="color: black;">)&nbsp;{</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>return&nbsp;</strong></span><span style="color: black;">String.format</span><span style="color: black;">(</span><span style="color: #2a00ff;">"0.%d"</span><span style="color: black;">,&nbsp;num</span><span style="color: black;">)</span><span style="color: black;">;</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: black;">}</span><br /><span style="color: white;">&nbsp;&nbsp;</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #3f5fbf;">/**</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;产生两个数之间的随机数</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;</span><span style="color: #7f9fbf;">@param&nbsp;</span><span style="color: #3f5fbf;">min</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;</span><span style="color: #7f9fbf;">@param&nbsp;</span><span style="color: #3f5fbf;">max</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;</span><span style="color: #3f5fbf;">*&nbsp;</span><span style="color: #7f9fbf;">@return</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;</span><span style="color: #3f5fbf;">*/</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>private&nbsp;</strong></span><span style="color: #7f0055;"><strong>int&nbsp;</strong></span><span style="color: black;">getRandomNum</span><span style="color: black;">(</span><span style="color: #7f0055;"><strong>double&nbsp;</strong></span><span style="color: black;">min,&nbsp;</span><span style="color: #7f0055;"><strong>double&nbsp;</strong></span><span style="color: black;">max</span><span style="color: black;">)&nbsp;{</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>return&nbsp;</strong></span><span style="color: black;">(</span><span style="color: #7f0055;"><strong>int</strong></span><span style="color: black;">)&nbsp;</span><span style="color: black;">min&nbsp;+&nbsp;</span><span style="color: black;">(</span><span style="color: #7f0055;"><strong>int</strong></span><span style="color: black;">)&nbsp;(</span><span style="color: black;">Math.random</span><span style="color: black;">()&nbsp;</span><span style="color: black;">*&nbsp;</span><span style="color: black;">(</span><span style="color: black;">max&nbsp;-&nbsp;min</span><span style="color: black;">))</span><span style="color: black;">;</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: black;">}</span><br /><span style="color: black;">}</span></code>       </td>     </tr></tbody></table></div><br />客户端代码调用方式：<br /><div class="java" align="left"><table bgcolor="#ffffff" border="0" cellpadding="3" cellspacing="0">   <tbody><tr>     <td align="left" nowrap="nowrap" valign="top"><code><span style="color: #7f0055;"><strong>public&nbsp;class&nbsp;</strong></span><span style="color: black;">Client&nbsp;</span><span style="color: black;">{</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: #7f0055;"><strong>public&nbsp;static&nbsp;</strong></span><span style="color: #7f0055;"><strong>void&nbsp;</strong></span><span style="color: black;">main</span><span style="color: black;">(</span><span style="color: black;">String</span><span style="color: black;">[]&nbsp;</span><span style="color: black;">args</span><span style="color: black;">)&nbsp;{</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">Builder&nbsp;builder&nbsp;=&nbsp;</span><span style="color: #7f0055;"><strong>new&nbsp;</strong></span><span style="color: black;">ConcreteOneBuilder</span><span style="color: black;">()</span><span style="color: black;">;</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">Director&nbsp;director&nbsp;=&nbsp;</span><span style="color: #7f0055;"><strong>new&nbsp;</strong></span><span style="color: black;">Director</span><span style="color: black;">(</span><span style="color: black;">builder</span><span style="color: black;">)</span><span style="color: black;">;</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">director.construct</span><span style="color: black;">()</span><span style="color: black;">;</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">Product&nbsp;product&nbsp;=&nbsp;builder.getProduct</span><span style="color: black;">()</span><span style="color: black;">;</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">System.out.println</span><span style="color: black;">(</span><span style="color: black;">product</span><span style="color: black;">)</span><span style="color: black;">;</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">System.out.println</span><span style="color: black;">()</span><span style="color: black;">;</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">System.out.println</span><span style="color: black;">(</span><span style="color: #2a00ff;">"现在输出第二个产品:\n"</span><span style="color: black;">)</span><span style="color: black;">;</span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">System.out.println</span><span style="color: black;">()</span><span style="color: black;">;</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">builder&nbsp;=&nbsp;</span><span style="color: #7f0055;"><strong>new&nbsp;</strong></span><span style="color: black;">ConcreteTwoBuilder</span><span style="color: black;">()</span><span style="color: black;">;</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">director&nbsp;=&nbsp;</span><span style="color: #7f0055;"><strong>new&nbsp;</strong></span><span style="color: black;">Director</span><span style="color: black;">(</span><span style="color: black;">builder</span><span style="color: black;">)</span><span style="color: black;">;</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">director.construct</span><span style="color: black;">()</span><span style="color: black;">;</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">product&nbsp;=&nbsp;builder.getProduct</span><span style="color: black;">()</span><span style="color: black;">;</span><br /><span style="color: white;"></span><br /><span style="color: white;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: black;">System.out.println</span><span style="color: black;">(</span><span style="color: black;">product</span><span style="color: black;">)</span><span style="color: black;">;</span><br /><span style="color: white;">&nbsp;&nbsp;</span><span style="color: black;">}</span><br /><span style="color: black;">}</span></code>       </td>     </tr></tbody></table></div><br />输入如下：<br /><br /><pre>产品型号(0.23)：<br /> *<br /> * *<br /> * * *<br /> * * * *<br /> * * * * *<br /> * * * * * *<br /> * * * * * * *<br /> * * * * * * * *<br /> * * * * * * * * *<br /> * * * * * * * * * *<br /> * * * * * * * * * * *<br /> * * * * * * * * * * * *<br /> * * * * * * * * * * * * *<br /> * * * * * * * * * * * * * *<br /> * * * * * * * * * * * * * * *<br /> * * * * * * * * * * * * * * * *<br /> * * * * * * * * * * * * * * * * *<br /> * * * * * * * * * * * * * * * * * *<br /> * * * * * * * * * * * * * * * * * * *<br /> * * * * * * * * * * * * * * * * * * * *<br /> * * * * * * * * * * * * * * * * * * * * *<br /> * * * * * * * * * * * * * * * * * * * * * *<br /><br /><br />现在输出第二个产品:<br /><br /><br />产品型号(0.17)：<br /> * * * * * * * * * * * * * * * * *<br />   * * * * * * * * * * * * * * * *<br />     * * * * * * * * * * * * * * *<br />       * * * * * * * * * * * * * *<br />         * * * * * * * * * * * * *<br />           * * * * * * * * * * * *<br />             * * * * * * * * * * *<br />               * * * * * * * * * *<br />                 * * * * * * * * *<br />                   * * * * * * * *<br />                     * * * * * * *<br />                       * * * * * *<br />                         * * * * *<br />                           * * * *<br />                             * * *<br />                               * *<br />                                 *</pre><br />每一次运行可能生成变形长度都会变好，这个变好有导向器进行控制着。<br /><br /><a href="http://cid-cf7746837803bc50.office.live.com/self.aspx/public/attachment/builder.zip">源文件下载</a><img src ="http://www.blogjava.net/yongboy/aggbug/346216.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2010-10-26 17:36 <a href="http://www.blogjava.net/yongboy/archive/2010/10/26/346216.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>枚举：不用那么单调，可以承担一些业务意义</title><link>http://www.blogjava.net/yongboy/archive/2010/10/22/346217.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Fri, 22 Oct 2010 03:52:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2010/10/22/346217.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/346217.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2010/10/22/346217.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/346217.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/346217.html</trackback:ping><description><![CDATA[人们大多顺手定义了一个枚举，仅仅是值的罗列，比如常见的一个，定义一个颜色枚举： <br /><div><pre><span style="color: blue;">public</span> enum Color {<br /> RED,GREEN,BLUE<br />}</pre></div>人们很少去想这么一个问题：枚举应该也可以承担一些业务意义。比如在这个Color枚举中，在某些情况下，我们需要得到颜色的名称，并且具有一个数字版本的ID，若能提供一个随机的颜色值就更好不过了。怎么办 ？ <br />大部分人们会另建立一个类，提供几个方法，对枚举进行操作，以达到目的。但是这些方法本身应该是Color自身的一些动作，只是被割裂了。下面的代码就能很好的完成以上要求： <span id="Code_Open_Text_962449"></span><br /><span id="Code_Open_Text_962449"><div><pre><span style="color: blue;">public</span> enum Color {<br /> RED("<span style="color: darkred;">red</span>",1),GREEN("<span style="color: darkred;">green</span>",2),BLUE("<span style="color: darkred;">blue</span>",3);<br /> <br /> <span style="color: blue;">private</span> String name;<br /> <span style="color: blue;">private</span> <span style="color: blue;">int</span> id;<br /> <br /> <span style="color: green;">/**<br />  * 必须的，使用一个构造函数用以初始化枚举常量<br />  * @param name<br />  * @param id<br />  */</span><br /> <span style="color: blue;">private</span> Color(String name, <span style="color: blue;">int</span> id){<br />  <span style="color: blue;">this</span>.name = name;<br />  <span style="color: blue;">this</span>.id = id;<br /> }<br /> <br /> <span style="color: blue;">public</span> String getName(){<br />  <span style="color: blue;">return</span> <span style="color: blue;">this</span>.name;<br /> }<br /> <br /> <span style="color: blue;">public</span> <span style="color: blue;">int</span> getId(){<br />  <span style="color: blue;">return</span> <span style="color: blue;">this</span>.id;<br /> }<br />}</pre></div>枚举是一个class变体，类似于 <strong>RED("<span style="color: darkred;">red</span>",1) </strong>可以看做是定了一个初始化Color的一个实例，其构造方法签名具有两个参数需要传入。   <br />现在的调用方式：   <br />Color.RED.getName(), Color.RED.getId()   <br />  <br />嗯，缺少了一个随机的颜色输出方法，下面我们在Color里面添加如下代码：   <br />  <div><pre> <span style="color: blue;">private</span> <span style="color: blue;">static</span> Random random = <span style="color: blue;">new</span> Random(47);<br /><br /> <span style="color: green;">/**<br />  * 随机提供一个颜色 使用方法 ： Color color = Color.random();<br />  * <br />  * @return Color<br />  */</span><br /> <span style="color: blue;">public</span> <span style="color: blue;">static</span> Color random() {<br />  Color[] colors = Color.values();<br />  <span style="color: blue;">return</span> colors[random.nextInt(colors.length)];<br /> }</pre></div><br />要想提供一个随机的颜色值，那就是静态的，不是一个具体颜色的本身属性。枚举都是具有values属性，返回一个数组。使用方法为&nbsp; <br />  <div><pre>Color color = Color.random();<br /><span style="color: green;">//一些属性的获取等操作</span></pre></div>有时，我们需要传入一个颜色值字符串获得对应的枚举值:   <br />  <div><pre> <span style="color: green;">/**<br />  * 构造一个Map，并初始化，便于插叙<br />  */</span><br /> <span style="color: blue;">private</span> <span style="color: blue;">static</span> Map&lt;String, Color&gt; clorNameMap = <span style="color: blue;">new</span> HashMap&lt;String, Color&gt;(<br />   Color.values().length);<br /> <span style="color: blue;">static</span> {<br />  <span style="color: blue;">for</span> (Color color : Color.values()) {<br />   clorNameMap.put(color.getName(), color);<br />  }<br /> }<br /> <br /> <span style="color: green;">/**<br />  * 通过颜色名称获取颜色枚举实例<br />  * @return<br />  */</span><br /> <span style="color: blue;">public</span> <span style="color: blue;">static</span> Color getByName(String colorName){<br />  <span style="color: blue;">return</span> clorNameMap.get(colorName);<br /> }</pre></div>构造了一个私有的Map对象，提升查询时的速度。使用方法:   <br />Color color = Color.getByName(&#8220;red&#8221;);   <br />若通过ID进行查询也可以按此方法，这里不再提供。下面为完整的代码：</span><br /><div><span id="Code_Open_Text_962449"><br />  </span><br /><span id="Code_Open_Text_962449"></span><br /><span id="Code_Open_Text_962449"><div><pre><span style="color: blue;">import</span> java.util.HashMap;<br /><span style="color: blue;">import</span> java.util.Map;<br /><span style="color: blue;">import</span> java.util.Random;<br /><br /><span style="color: green;">/**<br /> * 枚举可以承担一些业务意义<br /> * <br /> * @author yongboy@gmail.com<br /> * @date 2010-10-21<br /> */</span><br /><span style="color: blue;">public</span> enum Color {<br /> RED("<span style="color: darkred;">red</span>", 1), GREEN("<span style="color: darkred;">green</span>", 2), BLUE("<span style="color: darkred;">blue</span>", 3);<br /><br /> <span style="color: blue;">private</span> String name;<br /> <span style="color: blue;">private</span> <span style="color: blue;">int</span> id;<br /><br /> <span style="color: green;">/**<br />  * 必须的，使用一个构造函数用以初始化枚举常量<br />  * <br />  * @param name<br />  * @param id<br />  */</span><br /> <span style="color: blue;">private</span> Color(String name, <span style="color: blue;">int</span> id) {<br />  <span style="color: blue;">this</span>.name = name;<br />  <span style="color: blue;">this</span>.id = id;<br /> }<br /><br /> <span style="color: blue;">public</span> String getName() {<br />  <span style="color: blue;">return</span> <span style="color: blue;">this</span>.name;<br /> }<br /><br /> <span style="color: blue;">public</span> <span style="color: blue;">int</span> getId() {<br />  <span style="color: blue;">return</span> <span style="color: blue;">this</span>.id;<br /> }<br /><br /> <span style="color: blue;">private</span> <span style="color: blue;">static</span> Random random = <span style="color: blue;">new</span> Random(47);<br /><br /> <span style="color: green;">/**<br />  * 随机提供一个颜色 使用方法 ： Color color = Color.random();<br />  * <br />  * @return Color<br />  */</span><br /> <span style="color: blue;">public</span> <span style="color: blue;">static</span> Color random() {<br />  Color[] colors = Color.values();<br />  <span style="color: blue;">return</span> colors[random.nextInt(colors.length)];<br /> }<br /><br /> <span style="color: green;">/**<br />  * 构造一个Map，并初始化，便于插叙<br />  */</span><br /> <span style="color: blue;">private</span> <span style="color: blue;">static</span> Map&lt;String, Color&gt; clorNameMap = <span style="color: blue;">new</span> HashMap&lt;String, Color&gt;(<br />   Color.values().length);<br /> <span style="color: blue;">static</span> {<br />  <span style="color: blue;">for</span> (Color color : Color.values()) {<br />   clorNameMap.put(color.getName(), color);<br />  }<br /> }<br /><br /> <span style="color: green;">/**<br />  * 通过颜色名称获取颜色枚举实例<br />  * <br />  * @return<br />  */</span><br /> <span style="color: blue;">public</span> <span style="color: blue;">static</span> Color getByName(String colorName) {<br />  <span style="color: blue;">return</span> clorNameMap.get(colorName);<br /> }<br /><br /> <span style="color: blue;">public</span> String toString() {<br />  <span style="color: blue;">return</span> name + "<span style="color: darkred;">(</span>" + id + "<span style="color: darkred;">)</span>";<br /> }<br />}</pre><pre></pre></div>下面是UML示意图：<br /><a href="http://lh3.ggpht.com/_iP4ZGnOhL6U/TNDWMs709OI/AAAAAAAAAwY/8c_p8G1GfUg/s1600-h/enum%5B3%5D.png"><img alt="enum" src="http://lh4.ggpht.com/_iP4ZGnOhL6U/TNDWQGJneZI/AAAAAAAAAwc/S1WHNSaB__k/enum_thumb%5B1%5D.png?imgmax=800" style="border: 0px none; display: inline;" title="enum" border="0" /></a><br /><br />这里不是教大家获取枚举的一些编程技巧，那不是本意。只是想让一些看到本文的人注意一下：枚举可以承担一些业务意义。 </span></div><img src ="http://www.blogjava.net/yongboy/aggbug/346217.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2010-10-22 11:52 <a href="http://www.blogjava.net/yongboy/archive/2010/10/22/346217.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>观察者模式在线版：订阅-发布模型的在线示范</title><link>http://www.blogjava.net/yongboy/archive/2010/10/19/346218.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Tue, 19 Oct 2010 02:14:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2010/10/19/346218.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/346218.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2010/10/19/346218.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/346218.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/346218.html</trackback:ping><description><![CDATA[一直以来对观察者模式(Observer)一直理解为订阅发布模式，这样或许更好理解一些。现实中的博客RSS定制（在谷歌pubsubhubbub未出现以前，客户端都是被动的拉数据，PULL模式），需要客户端主动定时轮询方可。谷歌PUBSUBHUBBUB协议的问世，是一个创新，RSS主动推送的协议，非常实时，发布-订阅的最好典型。    <br />观察者模式的详细定义以及相关理论，可以参见《设计模式》，里面讲的很透彻。     <br />本文将带来一个在线版本的订阅-发布，用户添加一篇博文，所有订阅者可以马上得到通知，主动推送方式，避免了系统的大量无谓请求。虽有点PUBSUBHUBBUB协议的味道，但离实践还缺少很多，是一个演示。     <br />这个演示模拟的场景是关心特定博主的所有订阅者可以在新的博文发表之后的瞬间得到通知。从博文的发布到通知所有的订阅者知晓，可以以毫秒计算（比较理想的情况下，诸如服务器性能强劲，网络好，算法不错等）。但这里的订阅者是有限制的，必须要有一个可以被内容发布者服务器回调的URL地址，否则将不能实时通知到订阅者。这里强调的是可以被内容发布者服务器访问。演示模拟的场景在一个机器上多个站点之间进行，同一个局域网其它或者联网的环境下在理论上也都是可以的。     <br />需要先添加订阅者： <br /><a href="http://lh3.ggpht.com/_iP4ZGnOhL6U/TLz-3JIy0NI/AAAAAAAAAuE/Tf7rkHTyZ9Q/s1600-h/dingyue%5B13%5D.png"><img alt="dingyue" src="http://lh4.ggpht.com/_iP4ZGnOhL6U/TLz-4v3JOzI/AAAAAAAAAuI/c7aSv8xpOzI/dingyue_thumb%5B7%5D.png?imgmax=800" style="border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline;" title="dingyue" border="0" height="207" width="776" /></a> <br />若退订，步骤相同，致死要选择&#8220;退订&#8221;即可。<br /><br />&nbsp;<a href="http://lh4.ggpht.com/_iP4ZGnOhL6U/TLz-6Ny7EyI/AAAAAAAAAuM/Gk1FGfxeWwM/s1600-h/dingyue%5B9%5D.png"><img alt="dingyue" src="http://lh5.ggpht.com/_iP4ZGnOhL6U/TLz-7_LB3iI/AAAAAAAAAuQ/5mBJ_awWxN8/dingyue_thumb%5B5%5D.png?imgmax=800" style="border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline;" title="dingyue" border="0" height="205" width="768" /></a> <br />这个表单可以放在其它订阅者站点下面，只是FORM的URL地址要正确。<br />进入站点首页即可看到所有订阅者的回调地址：   <br /><a href="http://lh4.ggpht.com/_iP4ZGnOhL6U/TLz-8wVUEhI/AAAAAAAAAuU/bCzzxF3gk5Y/s1600-h/home%5B3%5D.png"><img alt="home" src="http://lh4.ggpht.com/_iP4ZGnOhL6U/TLz--uAxpYI/AAAAAAAAAuY/wFFnYUX8PoY/home_thumb%5B1%5D.png?imgmax=800" style="border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline;" title="home" border="0" height="295" width="779" /></a> <br /><br />有了订阅者之后，需要添加博文，测试我们的订阅者。   <br /><a href="http://lh5.ggpht.com/_iP4ZGnOhL6U/TLz_AI64E5I/AAAAAAAAAuc/e96chyb3ONA/s1600-h/Screenshot_2%5B4%5D.png"><img alt="Screenshot_2" src="http://lh3.ggpht.com/_iP4ZGnOhL6U/TLz_BU-lZYI/AAAAAAAAAug/vG9LZOW5QyE/Screenshot_2_thumb%5B2%5D.png?imgmax=800" style="border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline;" title="Screenshot_2" border="0" height="588" width="523" /></a>     <br />    <br />    <br />点击提交按钮之后，在各个站点终端下即可看到：     <br /><a href="http://lh3.ggpht.com/_iP4ZGnOhL6U/TLz_DHfmT9I/AAAAAAAAAuk/utOHr1kihRM/s1600-h/console%5B7%5D.png"><img alt="console" src="http://lh6.ggpht.com/_iP4ZGnOhL6U/TLz_GztWjTI/AAAAAAAAAuo/Ci4cx0S0nbU/console_thumb%5B5%5D.png?imgmax=800" style="border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline;" title="console" border="0" height="737" width="731" /></a> <br />为了演示，我们定义了两个订阅者站点: subscribeOne和subscribeTwo，一个显示所获取的数据，一个把获取的数据持久化到磁盘中。    <br />下面看看主站点的一些代码，首先来一个传统意义上观察者模式。<br />需要观察的对象，即目标 BlogService.java<br /><div><pre><span style="color: green;">/**<br /> * 博文操作<br /> * @author yongboy@gmail.com<br /> * @date 2010-10-18<br /> * @version 1.0<br /> */</span><br /><span style="color: blue;">public</span> <span style="color: blue;">class</span> BlogService {<br /> <span style="color: blue;">private</span> <span style="color: blue;">static</span> Set&lt;BlogObserver&gt; obserserList;<br /><br /> <span style="color: blue;">static</span> {<br />  obserserList = <span style="color: blue;">new</span> HashSet&lt;BlogObserver&gt;();<br /> }<br /><br /> <span style="color: blue;">public</span> <span style="color: blue;">void</span> addBlog(Blog blog) {<br />  System.out.println("<span style="color: darkred;">保存博文一些操作......</span>");<br />  <span style="color: green;">// 忽略具体逻辑</span><br />  System.out.println("<span style="color: darkred;">执行通知到所有的订阅者....</span>");<br />  updateObsersers(blog);<br /> }<br /><br /> <span style="color: blue;">private</span> <span style="color: blue;">void</span> updateObsersers(Blog blog) {<br />  <span style="color: blue;">for</span> (BlogObserver server : obserserList) {<br />   server.update(blog);<br />  }<br /> }<br /><br /> <span style="color: blue;">public</span> <span style="color: blue;">void</span> addObserver(BlogObserver blogObserver) {<br />  obserserList.add(blogObserver);<br /> }<br /><br /> <span style="color: blue;">public</span> <span style="color: blue;">void</span> removeObserver(BlogObserver blogObserver) {<br />  obserserList.remove(blogObserver);<br /> }<br /><br /> <span style="color: blue;">public</span> <span style="color: blue;">void</span> clearObserver() {<br />  obserserList.clear();<br /> }<br />}</pre><pre><br /></pre>可以看到内含观察者的一些简单的管理操作。</div>还需要定义了一个观察者，接口实现：<br /><br /><pre><span style="color: blue;">public</span> <span style="color: blue;">interface</span> BlogObserver {<br /> <span style="color: blue;">void</span> update(Blog blog);<br />}</pre><br />有两个具体的子类观察者，一个负责把博客的数据生成静态的文件，但这个不是重点，所以没有具体的代码附加；另外一个观察者负责把新的博文通知到所有的订阅者。<br /><span class="Apple-style-span" style="color: green; font-family: monospace;"><span class="Apple-style-span" style="white-space: pre;"><br /></span></span><br /><span class="Apple-style-span" style="color: green; font-family: monospace;"><span class="Apple-style-span" style="white-space: pre;">/**</span></span><br /><div><pre><span style="color: green;"> * 为新建的博文生成静态页面<br /> * <br /> * @author yongboy@gmail.com<br /> * @date 2010-10-19<br /> * @version 1.0<br /> */</span><br /><span style="color: blue;">public</span> <span style="color: blue;">class</span> BlogGenPageObserver <span style="color: blue;">implements</span> BlogObserver {<br /> <span style="color: blue;">public</span> <span style="color: blue;">void</span> update(Blog blog) {<br />  <span style="color: green;">// 具体生成代码省略</span><br />  System.out.println("<span style="color: darkred;">博文静态页面观察者开始工作......</span>");<br /> }<br />}</pre><span class="Apple-style-span" style="color: green; font-family: monospace;"><span class="Apple-style-span" style="white-space: pre;"><br /></span></span><br /><span class="Apple-style-span" style="color: green; font-family: monospace;"><span class="Apple-style-span" style="white-space: pre;">/**</span></span></div><div><pre><span style="color: green;"> * 定义一个博客信息推送观察者<br /> * @author yongboy@gmail.com<br /> * @date 2010-10-18<br /> * @version 1.0<br /> */</span><br /><span style="color: blue;">public</span> <span style="color: blue;">class</span> BlogNotifyObserver <span style="color: blue;">implements</span> BlogObserver {<br /><br /> <span style="color: blue;">public</span> <span style="color: blue;">void</span> update(Blog blog) {<br />  System.out.println("<span style="color: darkred;">博文推送观察者开始工作......</span>");<br />  <span style="color: green;">// 生成单篇博客的RSS</span><br />  RssService rssService = <span style="color: blue;">new</span> RssService(blog);<br />  String rssContent = rssService.ouputRss();<br />  <br />  <span style="color: green;">// 通知订阅者，分发博客内容</span><br />  NotifyService notifyService = <span style="color: blue;">new</span> NotifyService(rssContent);<br />  notifyService.doNotice();<br /> }<br />}</pre></div><br /><br />当前端发布了一篇博文后，会触发这两个观察者。<br /><br />订阅-发布模型，较适合于一个主端节点主动向各个订阅者节点主动推送信息，相比被动的拉模式，更为节省网络带宽以及服务器的性能。<br />在一个范围较大的局域网之间，彼此域之间的信息实时通知，也会是一个较好的应用。<br />在范围更大的互联网环境下，一个具有相当大的数量级订阅者的主机将可节省珍贵的机房带宽，经济收益不可小觑。<br /><br /><a href="http://cid-cf7746837803bc50.office.live.com/self.aspx/public/attachment/WebObserver.rar" target="_blank">源代码下载</a><img src ="http://www.blogjava.net/yongboy/aggbug/346218.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2010-10-19 10:14 <a href="http://www.blogjava.net/yongboy/archive/2010/10/19/346218.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>循环删除List数组容器里面元素</title><link>http://www.blogjava.net/yongboy/archive/2010/10/09/346219.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Sat, 09 Oct 2010 02:36:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2010/10/09/346219.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/346219.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2010/10/09/346219.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/346219.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/346219.html</trackback:ping><description><![CDATA[嗯，大部分都会遇到这个问题，定义一个List&lt;T&gt;数组，然后需要循环一下，删除其中一个元素，但会遇到类似问题：<br /><strong><span style="color: red;">java.util.ConcurrentModificationException</span></strong><br />怎么办，实用主义者会把List数组转换成Iterator进行迭代删除，一点问题都没有：<br /><div><pre> <span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">void</span> main(String[] args) {<br />  List&lt;Student&gt; students = pareStudents();<br />  <br />  System.<span style="color: blue;">out</span>.println("<span style="color: darkred;">size : </span>" + students.size());<br />  System.<span style="color: blue;">out</span>.println(students);<br />  <br />  System.<span style="color: blue;">out</span>.println("<span style="color: darkred;">delete Student with name xiaoi</span>");<br />  <br />  Iterator&lt;Student&gt;stuIter = students.iterator();<br />  <br />  <span style="color: blue;">while</span>(stuIter.hasNext()){<br />   Student stu = stuIter.next();<br />   <span style="color: blue;">if</span>(stu.getName().equals("<span style="color: darkred;">xiaoi</span>")){<br />    stuIter.remove();<br />   }<br />  }<br />  <br />  System.<span style="color: blue;">out</span>.println("<span style="color: darkred;">size : </span>" + students.size());<br />  System.<span style="color: blue;">out</span>.println(students);<br /> }</pre></div><br />Iterator进行循环操作，然后删除，是很安全的。可以解决一些问题。但不要再使用Iterator的时候使用students.remove(stu)，一样会给出 <strong><span style="color: red;">java.util.ConcurrentModificationException </span></strong>错误。<br /><br /><br />另一个方法就是重新构建一个List,把原先的students 数组作为参数传递进去即可，虽然生成了一个全新的数组，但都是Student对象的引用，多个引用的地址数组而已。<br /><div><br /><br /><pre> <span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">void</span> main(String[] args) {<br />  List&lt;Student&gt; students = pareStudents();<br />  <br />  System.out.println("<span style="color: darkred;">size : </span>" + students.size());<br />  System.out.println(students);<br />  <br />  System.out.println("<span style="color: darkred;">delete Student with name xiaoi</span>");<br />  <span style="color: blue;">for</span>(Student s : <span style="color: blue;">new</span> ArrayList&lt;Student&gt;(students)){<br />   <span style="color: blue;">if</span>(s.getName().equals("<span style="color: darkred;">xiaoi</span>")){<br />    students.remove(s);<br />   }<br />  }<br />  <br />  System.out.println("<span style="color: darkred;">size : </span>" + students.size());<br />  System.out.println(students);<br /> }</pre></div><br /><br />需要那一种方式，那就自便了，个人倾向于使用Iterator。<br />完整测试代码如下：<br /><br /><div><pre><span style="color: blue;">public</span> <span style="color: blue;">class</span> DeleteList {<br /> <span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: blue;">class</span> Student{<br />  <span style="color: blue;">private</span> String name;<br />  <span style="color: blue;">private</span> <span style="color: blue;">int</span> age;<br /><br />  <span style="color: blue;">public</span> Student(String name, <span style="color: blue;">int</span> age) {<br />   <span style="color: blue;">this</span>.name = name;<br />   <span style="color: blue;">this</span>.age = age;<br />  }<br />  <br />  <span style="color: blue;">public</span> <span style="color: blue;">int</span> getAge() {<br />   <span style="color: blue;">return</span> age;<br />  }<br />  <br />  <span style="color: blue;">public</span> <span style="color: blue;">void</span> setAge(<span style="color: blue;">int</span> age) {<br />   <span style="color: blue;">this</span>.age = age;<br />  }<br />  <br />  <span style="color: blue;">public</span> String getName() {<br />   <span style="color: blue;">return</span> name;<br />  }<br />  <span style="color: blue;">public</span> <span style="color: blue;">void</span> setName(String name) {<br />   <span style="color: blue;">this</span>.name = name;<br />  }<br /><br />  <span style="color: blue;">public</span> <span style="color: blue;">int</span> hashCode() {<br />   <span style="color: blue;">return</span> name.hashCode();<br />  }<br /><br />  <span style="color: blue;">public</span> <span style="color: blue;">boolean</span> equals(Object obj) {<br />   <span style="color: blue;">if</span>(obj == <span style="color: blue;">null</span> || !(obj <span style="color: blue;">instanceof</span> Student)){<br />    <span style="color: blue;">return</span> <span style="color: blue;">false</span>;<br />   }<br />   <br />   Student objStu = (Student)obj;<br />   <span style="color: blue;">return</span> objStu.getName().equals(<span style="color: blue;">this</span>.getName()) &amp;&amp; objStu.getAge() == <span style="color: blue;">this</span>.getAge();<br />  }<br />  <br />  <span style="color: blue;">public</span> String toString(){<br />   <span style="color: blue;">return</span> name + "<span style="color: darkred;"> : </span>" + age;<br />  }<br /> }<br /> <br /> <span style="color: blue;">private</span> <span style="color: blue;">static</span> List&lt;Student&gt; pareStudents(){<br />  ArrayList&lt;Student&gt; students = <span style="color: blue;">new</span> ArrayList&lt;Student&gt;();<br />  <br />  students.add(<span style="color: blue;">new</span> Student("<span style="color: darkred;">xiaoi</span>", 18));<br />  students.add(<span style="color: blue;">new</span> Student("<span style="color: darkred;">xiaoxin</span>", 19));  <br />  students.add(<span style="color: blue;">new</span> Student("<span style="color: darkred;">john</span>", 20));<br />  students.add(<span style="color: blue;">new</span> Student("<span style="color: darkred;">xiaomei</span>", 23));<br />  <br />  <span style="color: blue;">return</span> students;<br /> }<br /> <br /> <span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">void</span> main(String[] args) {<br />  List&lt;Student&gt; students = pareStudents();<br />  <br />  System.out.println("<span style="color: darkred;">size : </span>" + students.size());<br />  System.out.println(students);<br />  <br />  System.out.println("<span style="color: darkred;">delete Student with name xiaoi</span>");<br />  <span style="color: blue;">for</span>(Student s : <span style="color: blue;">new</span> ArrayList&lt;Student&gt;(students)){<br />   <span style="color: blue;">if</span>(s.getName().equals("<span style="color: darkred;">xiaoi</span>")){<br />    students.remove(s);<br />   }<br />  }<br />  <br />  System.out.println("<span style="color: darkred;">size : </span>" + students.size());<br />  System.out.println(students);<br /> }<br /> <br /> <span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">void</span> main2(String[] args) {<br />  List&lt;Student&gt; students = pareStudents();<br />  <br />  System.out.println("<span style="color: darkred;">size : </span>" + students.size());<br />  System.out.println(students);<br />  <br />  System.out.println("<span style="color: darkred;">delete Student with name xiaoi</span>");<br />  <br />  Iterator&lt;Student&gt;stuIter = students.iterator();<br />  <br />  <span style="color: blue;">while</span>(stuIter.hasNext()){<br />   Student stu = stuIter.next();<br />   <span style="color: blue;">if</span>(stu.getName().equals("<span style="color: darkred;">xiaoi</span>")){<br />    stuIter.remove();<br />   }<br />  }<br />  <br />  System.out.println("<span style="color: darkred;">size : </span>" + students.size());<br />  System.out.println(students);<br /> }<br />}</pre><pre><br /></pre><pre><span class="Apple-style-span" style="font-family: Simsun; white-space: normal;">Iterator 是工作在一个独立的线程中，并且拥有一个 mutex 锁。 Iterator 被创建之后会建立一个指向原来对象的单链索引表，当原来的对象数量发生变化时，这个索引表的内容不会同步改变，所以当索引指针往后移动的时候就找不到要迭 代的对象，所以按照 fail-fast 原则 Iterator 会马上抛出</span><span class="Apple-style-span" style="font-family: Simsun; white-space: normal;">&nbsp;</span><span class="Apple-style-span" style="font-family: Simsun; white-space: normal;"><span class="hilite1">java</span></span><span class="Apple-style-span" style="font-family: Simsun; white-space: normal;">.</span><span class="Apple-style-span" style="font-family: Simsun; white-space: normal;"><span class="hilite2">util</span></span><span class="Apple-style-span" style="font-family: Simsun; white-space: normal;">.</span><span class="Apple-style-span" style="font-family: Simsun; white-space: normal;"><span class="hilite3">ConcurrentModificationException</span></span><span class="Apple-style-span" style="font-family: Simsun; white-space: normal;">&nbsp;</span><span class="Apple-style-span" style="font-family: Simsun; white-space: normal;">异常。</span></pre><pre><span class="Apple-style-span" style="font-family: Simsun; white-space: normal;"><br /></span><span class="Apple-style-span" style="font-family: Simsun; white-space: normal;">所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象， Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。</span></pre><pre><span class="Apple-style-span" style="font-family: Simsun; white-space: normal;"><br /></span></pre><pre><span class="Apple-style-span" style="font-family: Simsun;"><span class="Apple-style-span" style="white-space: normal;">refer url :&nbsp;</span></span><a href="http://www.cnblogs.com/iloveu/archive/2009/06/23/1509385.html">http://www.cnblogs.com/iloveu/archive/2009/06/23/1509385.html</a></pre></div><img src ="http://www.blogjava.net/yongboy/aggbug/346219.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2010-10-09 10:36 <a href="http://www.blogjava.net/yongboy/archive/2010/10/09/346219.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>模板模式以及java算法的复习</title><link>http://www.blogjava.net/yongboy/archive/2010/10/06/346220.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Wed, 06 Oct 2010 02:59:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2010/10/06/346220.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/346220.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2010/10/06/346220.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/346220.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/346220.html</trackback:ping><description><![CDATA[针对常用的算法进行重新复习了一下，结合对象数组排序，使用模板模式封装了一部分，各个子类实现自己的对象数组排序算法。里面稍微涉及到了适配器、策略模式等。使用了泛型，嗯，会带来一部分代码的复用。<br />定义一个算法抽象基类：<br /><div><pre><span style="color: green;">/**<br /> * 对象数组排序算法，藉此复习几种常见排序算法<br /> * <br /> * 模板模式<br /> * <br /> **/</span><br /><span style="color: blue;">public</span> <span style="color: blue;">abstract</span> <span style="color: blue;">class</span> Sort {<br /><br /> <span style="color: green;">/**<br />  * 对象数组排序<br />  * @param &lt;T&gt;<br />  * @param ts 传入要排序的对象数组<br />  * @param c 需要传入的自定义比较器<br />  */</span><br /> <span style="color: blue;">public</span> <span style="color: blue;">abstract</span> &lt;T&gt; <span style="color: blue;">void</span> sort(T[] ts, Comparator&lt;? <span style="color: blue;">super</span> T&gt; c);<br /><br /> <span style="color: green;">/**<br />  * 对象数组排序<br />  * @param &lt;T&gt;<br />  * @param datas 传入的对象必须已经实现了Comparable接口<br />  */</span><br /> <span style="color: blue;">public</span> &lt;T <span style="color: blue;">extends</span> Comparable&lt;T&gt;&gt; <span style="color: blue;">void</span> sort(T[] datas) {<br />  sort(datas, <span style="color: blue;">new</span> ComparatorAdapter&lt;T&gt;());<br /> }<br /><br /> <span style="color: green;">/**<br />  * 定义一个比较适配器内部类,使Comparable接口适配成Comparator接口<br />  * <br />  * @author xiaomin<br />  * <br />  * @param &lt;T&gt;<br />  */</span><br /> <span style="color: blue;">private</span> <span style="color: blue;">class</span> ComparatorAdapter&lt;T <span style="color: blue;">extends</span> Comparable&lt;T&gt;&gt; <span style="color: blue;">implements</span><br />   Comparator&lt;T&gt; {<br />  <span style="color: blue;">public</span> <span style="color: blue;">int</span> compare(T o1, T o2) {<br />   <span style="color: blue;">return</span> o1.compareTo(o2);<br />  }<br /> }<br /><br /> <span style="color: green;">/**<br />  * 交换对象数组里面的两个元素位置<br />  * @param &lt;T&gt;<br />  * @param ints<br />  * @param index1<br />  * @param index2<br />  */</span><br /> <span style="color: blue;">protected</span> &lt;T&gt; <span style="color: blue;">void</span> swap(T[] ints, <span style="color: blue;">int</span> index1, <span style="color: blue;">int</span> index2) {<br />  T temp = ints[index1];<br /><br />  ints[index1] = ints[index2];<br /><br />  ints[index2] = temp;<br /> }<br />}</pre></div>一个冒泡算法实现：<br /><div><pre><span style="color: green;">/**<br /> * 冒泡排序----交换排序的一种<br /> * 方法：相邻两元素进行比较，如有需要则进行交换，每完成一次循环就将最大元素排在最后（如从小到大排序），下一次循环是将其他的数进行类似操作。<br /> * 性能：比较次数O(n^2),n^2/2；交换次数O(n^2),n^2/4<br /> *<br />**/</span><br /><span style="color: blue;">public</span> <span style="color: blue;">class</span> Bubble <span style="color: blue;">extends</span> Sort{<br /><br /> @Override<br /> <span style="color: blue;">public</span> &lt;T&gt; <span style="color: blue;">void</span> sort(T[] datas, Comparator&lt;? <span style="color: blue;">super</span> T&gt; c){<br />  <span style="color: blue;">for</span>(<span style="color: blue;">int</span> i = (datas.length - 1); i &gt; 0; i--){<br />   <span style="color: blue;">for</span>(<span style="color: blue;">int</span> j = 0; j &lt; i; j++){<br />    <span style="color: blue;">if</span>(c.compare(datas[j], datas[j + 1]) &gt; 0){<br />     <span style="color: blue;">super</span>.swap(datas, j, j+1);<br />    }<br />   }<br />  }<br /> }<br /><br /> <span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">void</span> main(String ... args){<br />  Bubble b = <span style="color: blue;">new</span> Bubble();<br />  Integer [] ints = {1, 23, 0, 2, 356, 367, 6,-1, 256};<br />  b.sort(ints);<br />  <br />  System.out.println(Arrays.toString(ints));<br /> }<br />}</pre></div>一个插入排序：<br /><div><pre><span style="color: green;">/**<br /> * 插入排序<br /> * 方法：将一个记录插入到已排好序的有序表（有可能是空表）中,从而得到一个新的记录数增1的有序表。<br /> * 性能：比较次数O(n^2),n^2/4<br /> *       复制次数O(n),n^2/4<br /> *       比较次数是前两者的一般，而复制所需的CPU时间较交换少，所以性能上比冒泡排序提高一倍多，而比选择排序也要快。<br /> *<br /> */</span><br /><span style="color: blue;">public</span> <span style="color: blue;">class</span> Insert <span style="color: blue;">extends</span> Sort{<br /><br /> @Override<br /> <span style="color: blue;">public</span> &lt;T&gt; <span style="color: blue;">void</span> sort(T[] datas, Comparator&lt;? <span style="color: blue;">super</span> T&gt; c){<br />  <span style="color: blue;">for</span>(<span style="color: blue;">int</span> i = 0; i &lt; datas.length; i++){<br />   <span style="color: blue;">for</span>(<span style="color: blue;">int</span> j = i; j &gt; 0; j--){<br />    <span style="color: blue;">if</span>(c.compare(datas[j -1],datas[j]) &gt; 0){<br />     <span style="color: blue;">super</span>.swap(datas, j-1, j);<br />    }<br />   }<br />  }<br /> }<br /><br /> <span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">void</span> main(String [] args){<br />  Insert insert = <span style="color: blue;">new</span> Insert();<br />  Double [] doubles = {1.0, 0.3, 3.4, -0.3, 3.0,3.0, 0.34};<br />  <br />  insert.sort(doubles);<br />  <br />  System.out.println(Arrays.toString(doubles));<br /> }<br />}</pre></div>其它两个，快速，选择排序不再一一粘贴。<br />附加一个客户端测试类：<br /><div><pre><span style="color: blue;">public</span> <span style="color: blue;">class</span> Client {<br /><br /> <span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">void</span> main(String[] args) {<br />  Person[] persons = { <span style="color: blue;">new</span> Person("<span style="color: darkred;">a</span>", 12), <span style="color: blue;">new</span> Person("<span style="color: darkred;">b</span>", 10),<br />    <span style="color: blue;">new</span> Person("<span style="color: darkred;">demo</span>", 23), <span style="color: blue;">new</span> Person("<span style="color: darkred;">hello</span>", 22),<br />    <span style="color: blue;">new</span> Person("<span style="color: darkred;">hello</span>", 32), <span style="color: blue;">new</span> Person("<span style="color: darkred;">xiaomeng</span>", 2) };<br />  <br />  Person [] selectPersons = persons.clone();<br />  <br />  Person [] quickPersons = persons.clone();<br />  <br />  Person [] quickCustomPersons = persons.clone();<br />  <br />  Person [] insertPersons = persons.clone();<br /><br />  System.out.println("<span style="color: darkred;">排序前 ......</span>");<br />  System.out.println(Arrays.toString(persons));<br />  System.out.println();<br />  <br />  System.out.println("<span style="color: darkred;">冒泡排序后 ......</span>");<br />  <span style="color: blue;">new</span> Bubble().sort(persons);<br />  System.out.println(Arrays.toString(persons));<br />  System.out.println();  <br /><br />  System.out.println("<span style="color: darkred;">选择排序后 ......</span>");<br />  <span style="color: blue;">new</span> Select().sort(selectPersons);<br />  System.out.println(Arrays.toString(selectPersons));<br />  System.out.println();<br />  <br />  System.out.println("<span style="color: darkred;">插入排序后 ......</span>");<br />  <span style="color: blue;">new</span> Insert().sort(insertPersons);<br />  System.out.println(Arrays.toString(insertPersons));<br />  System.out.println();<br />  <br />  System.out.println("<span style="color: darkred;">快速排序后 ......</span>");<br />  <span style="color: blue;">new</span> Quick().sort(quickPersons);<br />  System.out.println(Arrays.toString(quickPersons));<br />  System.out.println();<br /><br />  System.out.println("<span style="color: darkred;">使用快速自定义排序 ......</span>");<br />  <span style="color: blue;">new</span> Quick().sort(quickCustomPersons, <span style="color: blue;">new</span> Comparator&lt;Person&gt;() {<br />   <span style="color: blue;">public</span> <span style="color: blue;">int</span> compare(Person o1, Person o2) {<span style="color: green;">// 倒叙排列    </span><br />    <span style="color: blue;">return</span> o1.getAge() &gt; o2.getAge() ? -1 : (o1.getAge() == o2.getAge() ? 0 : 1);<br />   }<br />  });<br /><br />  System.out.println(Arrays.toString(quickCustomPersons));<br /> }<br />}<br /><br /><span style="color: blue;">class</span> Person <span style="color: blue;">implements</span> Serializable, Comparable&lt;Person&gt; {<br /> <span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: blue;">final</span> <span style="color: blue;">long</span> serialVersionUID = -23536L;<br /> <br /> <span style="color: blue;">private</span> String name;<br /> <span style="color: blue;">private</span> <span style="color: blue;">int</span> age;<br /><br /> <span style="color: blue;">public</span> Person() {<br /> }<br /><br /> <span style="color: blue;">public</span> Person(String name, <span style="color: blue;">int</span> age) {<br />  <span style="color: blue;">this</span>.name = name;<br />  <span style="color: blue;">this</span>.age = age;<br /> }<br /><br /> <span style="color: blue;">public</span> String getName() {<br />  <span style="color: blue;">return</span> name;<br /> }<br /><br /> <span style="color: blue;">public</span> <span style="color: blue;">void</span> setName(String name) {<br />  <span style="color: blue;">this</span>.name = name;<br /> }<br /><br /> <span style="color: blue;">public</span> <span style="color: blue;">int</span> getAge() {<br />  <span style="color: blue;">return</span> age;<br /> }<br /><br /> <span style="color: blue;">public</span> <span style="color: blue;">void</span> setAge(<span style="color: blue;">int</span> age) {<br />  <span style="color: blue;">this</span>.age = age;<br /> }<br /> <br /> <span style="color: green;">// 正序排列</span><br /> <span style="color: blue;">public</span> <span style="color: blue;">int</span> compareTo(Person o) {<br />  <span style="color: blue;">if</span> (o == <span style="color: blue;">null</span>)<br />   <span style="color: blue;">return</span> -1;<br /><br />  <span style="color: blue;">return</span> <span style="color: blue;">this</span>.getAge() &lt; o.getAge() ? -1 : (<span style="color: blue;">this</span>.getAge() == o.getAge() ? 0 : 1);<br /> }<br /><br /> <span style="color: blue;">public</span> String toString() {<br />  <span style="color: blue;">return</span> "<span style="color: darkred;">name : </span>" + getName() + "<span style="color: darkred;"> age : </span>" + getAge();<br /> }<br />}</pre><pre><br /></pre></div>代码打包下载地址: <a href="http://cid-cf7746837803bc50.office.live.com/self.aspx/public/attachment/sort.zip" target="_blank">下载</a><br /><br /><br /><br /><br /><img src ="http://www.blogjava.net/yongboy/aggbug/346220.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2010-10-06 10:59 <a href="http://www.blogjava.net/yongboy/archive/2010/10/06/346220.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA 两种排序方式复习</title><link>http://www.blogjava.net/yongboy/archive/2010/10/05/346221.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Tue, 05 Oct 2010 09:24:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2010/10/05/346221.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/346221.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2010/10/05/346221.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/346221.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/346221.html</trackback:ping><description><![CDATA[本文演示了在一个java文件中集成了两种排序方式，自定义冒泡排序算法进行区别于JDK的内置排序算法。<br />传统模式下的两种排序算法：<br /><div><pre><span style="color: green;">/**<br /> * JAVA两种排序复习<br /> * 针对具体对象编写相应的排序代码，这一部分是经常变动的部分<br /> * 排序Arrays.sort方法为不变的部分，封装了具体排序算法<br /> * 两者结合，一个策略模式出来了<br /> * <br /> * @author xiaomin<br /> */</span><br /><span style="color: blue;">public</span> <span style="color: blue;">class</span> Person <span style="color: blue;">implements</span> Serializable, Comparable&lt;Person&gt; {<br /> <span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: blue;">final</span> <span style="color: blue;">long</span> serialVersionUID = -23536L;<br /> <br /> <span style="color: blue;">private</span> String name;<br /> <span style="color: blue;">private</span> <span style="color: blue;">int</span> age;<br /><br /> <span style="color: blue;">public</span> Person() {<br /> }<br /><br /> <span style="color: blue;">public</span> Person(String name, <span style="color: blue;">int</span> age) {<br />  <span style="color: blue;">this</span>.name = name;<br />  <span style="color: blue;">this</span>.age = age;<br /> }<br /><br /> <span style="color: blue;">public</span> String getName() {<br />  <span style="color: blue;">return</span> name;<br /> }<br /><br /> <span style="color: blue;">public</span> <span style="color: blue;">void</span> setName(String name) {<br />  <span style="color: blue;">this</span>.name = name;<br /> }<br /><br /> <span style="color: blue;">public</span> <span style="color: blue;">int</span> getAge() {<br />  <span style="color: blue;">return</span> age;<br /> }<br /><br /> <span style="color: blue;">public</span> <span style="color: blue;">void</span> setAge(<span style="color: blue;">int</span> age) {<br />  <span style="color: blue;">this</span>.age = age;<br /> }<br /> <br /> <span style="color: green;">// 正序排列,针对具体bean的排序,经常变动的部分</span><br /> <span style="color: blue;">public</span> <span style="color: blue;">int</span> compareTo(Person o) {<br />  <span style="color: blue;">if</span> (o == <span style="color: blue;">null</span>)<br />   <span style="color: blue;">return</span> -1;<br /><br />  <span style="color: blue;">return</span> <span style="color: blue;">this</span>.getAge() &lt; o.getAge() ? -1 : (<span style="color: blue;">this</span>.getAge() == o.getAge() ? 0 : 1);<br /> }<br /><br /> <span style="color: blue;">public</span> String toString() {<br />  <span style="color: blue;">return</span> "<span style="color: darkred;">name : </span>" + getName() + "<span style="color: darkred;"> age : </span>" + getAge();<br /> }<br /><br /> <span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">void</span> main(String... args) {<br />  Person[] persons = { <span style="color: blue;">new</span> Person("<span style="color: darkred;">a</span>", 12), <span style="color: blue;">new</span> Person("<span style="color: darkred;">b</span>", 10),<br />    <span style="color: blue;">new</span> Person("<span style="color: darkred;">demo</span>", 23), <span style="color: blue;">new</span> Person("<span style="color: darkred;">hello</span>", 22),<br />    <span style="color: blue;">new</span> Person("<span style="color: darkred;">hello</span>", 32) };<br /><br />  System.out.println("<span style="color: darkred;">排序前 ......</span>");<br />  System.out.println(Arrays.toString(persons));<br /><br />  System.out.println("<span style="color: darkred;">排序后 ......</span>");<br />  Arrays.sort(persons);<br />  System.out.println(Arrays.toString(persons));<br /><br />  System.out.println("<span style="color: darkred;">使用自定义排序 ......</span>");<br />  <br />  <span style="color: green;">// 适用于没有继承Comparable的bean或需要自行定制的排序方式</span><br />  Arrays.sort(persons, <span style="color: blue;">new</span> Comparator&lt;Person&gt;() {<br />   <span style="color: blue;">public</span> <span style="color: blue;">int</span> compare(Person o1, Person o2) {<span style="color: green;">// 倒叙排列    </span><br />    <span style="color: blue;">return</span> o1.getAge() &gt; o2.getAge() ? -1 : (o1.getAge() == o2.getAge() ? 0 : 1);<br />   }<br />  });<br /><br />  System.out.println(Arrays.toString(persons));<br /> }<br />}</pre></div><br /><div>一般还是建议使用ＪＤＫ内置的排序算法，当然我们还是可以自己编写自定义的排序算法，下面代码仅仅为了演示。</div><pre><span style="color: green;">/**<br /> * 自定义冒泡排序算法，演示使用，用以替代系统默认的Arrays.sort<br /> * @author xiaomin<br /> *<br /> */</span><br /><span style="color: blue;">public</span> <span style="color: blue;">class</span> BubbleSort { <br /> <span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">void</span> main(String[] args) {<br />  Person[] persons = { <span style="color: blue;">new</span> Person("<span style="color: darkred;">a</span>", 12), <span style="color: blue;">new</span> Person("<span style="color: darkred;">b</span>", 10),<br />    <span style="color: blue;">new</span> Person("<span style="color: darkred;">demo</span>", 23), <span style="color: blue;">new</span> Person("<span style="color: darkred;">hello</span>", 22),<br />    <span style="color: blue;">new</span> Person("<span style="color: darkred;">hello</span>", 32) };<br /><br />  System.out.println("<span style="color: darkred;">排序前 ......</span>");<br />  System.out.println(Arrays.toString(persons));<br /><br />  System.out.println("<span style="color: darkred;">排序后 ......</span>");<br />  bubble(persons);<br />  System.out.println(Arrays.toString(persons));<br /><br />  System.out.println("<span style="color: darkred;">使用自定义排序 ......</span>");<br />  <br />  <span style="color: green;">// 适用于没有继承Comparable的bean或需要自行定制的排序方式</span><br />  bubble(persons, <span style="color: blue;">new</span> Comparator&lt;Person&gt;() {<br />   <span style="color: blue;">public</span> <span style="color: blue;">int</span> compare(Person o1, Person o2) {<span style="color: green;">// 倒叙排列    </span><br />    <span style="color: blue;">return</span> o1.getAge() &gt; o2.getAge() ? -1 : (o1.getAge() == o2.getAge() ? 0 : 1);<br />   }<br />  });<br /><br />  System.out.println(Arrays.toString(persons));<br /> }<br /> <br /> <span style="color: blue;">public</span> <span style="color: blue;">static</span> &lt;T&gt; <span style="color: blue;">void</span> bubble(T [] ts, Comparator&lt;? <span style="color: blue;">super</span> T&gt; c){  <br />  <span style="color: blue;">for</span>(<span style="color: blue;">int</span> i = 0; i &lt; ts.length; i ++){<br />   <span style="color: blue;">for</span>(<span style="color: blue;">int</span> j = ts.length -1; j &gt; i; j--){<br />    <span style="color: blue;">if</span>(c.compare(ts[j-1], ts[j]) &gt; 0){<br />     swap(ts, j-1, j);<br />    }<br />   }<br />  }<br /> }<br /> <br /> <span style="color: blue;">public</span> <span style="color: blue;">static</span> &lt;T <span style="color: blue;">extends</span> Comparable&lt;T&gt;&gt; <span style="color: blue;">void</span> bubble(T [] ts){  <br />  <span style="color: blue;">for</span>(<span style="color: blue;">int</span> i = 0; i &lt; ts.length; i ++){<br />   <span style="color: blue;">for</span>(<span style="color: blue;">int</span> j = ts.length -1; j &gt; i; j--){<br />    <span style="color: blue;">if</span>(ts[j-1].compareTo(ts[j]) &gt; 0){<br />     swap(ts, j-1, j);<br />    }<br />   }<br />  }<br /> }<br /> <br /> <span style="color: blue;">private</span> <span style="color: blue;">static</span> &lt;T&gt; <span style="color: blue;">void</span> swap(T [] ints,<span style="color: blue;">int</span> index1, <span style="color: blue;">int</span> index2){<br />  T temp = ints[index1];<br />  <br />  ints[index1] = ints[index2];<br />  <br />  ints[index2] = temp;<br /> }<br />}</pre><pre>&nbsp;</pre><pre>两种排序输出结果：</pre><blockquote><em>排序前 ......<br />[name : a age : 12, name : b age : 10, name : demo age : 23, name : hello age : 22, name : hello age : 32]<br />排序后 ......<br />[name : b age : 10, name : a age : 12, name : hello age : 22, name : demo age : 23, name : hello age : 32]<br />使用自定义排序 ......<br />[name : hello age : 32, name : demo age : 23, name : hello age : 22, name : a age : 12, name : b age : 10]</em><br /><em>若有时间，也可以实现其它常见的排序算法。</em></blockquote><br />关于 Arrays的Sort算法分析 ： <a href="http://www.slideshare.net/zianed/arrayssort">http://www.slideshare.net/zianed/arrayssort</a>　可以参考一下。<img src ="http://www.blogjava.net/yongboy/aggbug/346221.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2010-10-05 17:24 <a href="http://www.blogjava.net/yongboy/archive/2010/10/05/346221.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA Stack（栈）学习代码</title><link>http://www.blogjava.net/yongboy/archive/2010/10/05/346222.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Tue, 05 Oct 2010 03:36:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2010/10/05/346222.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/346222.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2010/10/05/346222.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/346222.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/346222.html</trackback:ping><description><![CDATA[近日了解一下栈的概念，LIFO，后进先出，顺手写了几个实现，添加泛型支持，特贴于此：<br /><br /><div><pre>/**<br /> * 定义一个不可变栈<br /> * <br /> * @author xiaomin<br /> * <br /> * @param <span style="color: blue;">&lt;</span><span style="color: maroon;">T</span><span style="color: blue;">&gt;</span><br /> */<br />public class DefaultStack<span style="color: blue;">&lt;</span><span style="color: maroon;">T</span> <span style="color: red;">extends</span> <span style="color: red;">Serializable</span><span style="color: blue;">&gt;</span> implements Stack<span style="color: blue;">&lt;</span><span style="color: maroon;">T</span><span style="color: blue;">&gt;</span> {<br /><br /> private int size;<br /><br /> private Object[] values;<br /><br /> private int curr;<br /><br /> public DefaultStack(int size) {<br />  this.size = size;<br /><br />  curr = -1;<br /><br />  values = new Object[size];<br /> }<br /><br /> @Override<br /> public void push(T t) {<br />  if ((size - 1) == curr) {<br />   throw new UnsupportedOperationException("The Stack is full now !");<br />  }<br /><br />  curr++;<br />  values[curr] = t;<br /> }<br /><br /> @SuppressWarnings("unchecked")<br /> @Override<br /> public T pop() {<br />  if (curr <span style="color: blue;">&lt;</span> 0) {<br />   throw new UnsupportedOperationException("The Stack is empty now !");<br />  }<br /><br />  return (T) values[curr--];<br /> }<br /><br /> @Override<br /> public boolean end() {<br />  return curr == -1;<br /> }<br />}</pre></div>有三个实现：<br /><div><pre><span style="color: green;">/**<br /> * 定义一个链接结构的栈<br /> * <br /> * @author xiaomin<br /> * <br /> * @param &lt;T&gt;<br /> */</span><br /><span style="color: blue;">public</span> <span style="color: blue;">class</span> LinkStack&lt;T <span style="color: blue;">extends</span> Serializable&gt; <span style="color: blue;">implements</span> Stack&lt;T&gt; {<br /><br /> <span style="color: green;">/**<br />  * 定义一个节点<br />  * <br />  * @author xiaomin<br />  * <br />  */</span><br /> <span style="color: blue;">private</span> <span style="color: blue;">class</span> Node <span style="color: blue;">implements</span> Serializable {<br />  <span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: blue;">final</span> <span style="color: blue;">long</span> serialVersionUID = 1L;<br /><br />  <span style="color: blue;">private</span> T value;<br />  <span style="color: blue;">private</span> Node pre;<br /><br />  <span style="color: green;">// 构造一个空值</span><br />  <span style="color: blue;">public</span> Node() {<br />   value = <span style="color: blue;">null</span>;<br />   pre = <span style="color: blue;">null</span>;<br />  }<br /><br />  <span style="color: blue;">public</span> Node(T value, Node pre) {<br />   <span style="color: blue;">this</span>.value = value;<br />   <span style="color: blue;">this</span>.pre = top;<br />  }<br /> }<br /><br /> <span style="color: blue;">private</span> Node top = <span style="color: blue;">new</span> Node();<br /><br /> @Override<br /> <span style="color: blue;">public</span> <span style="color: blue;">void</span> push(T t) {<br />  top = <span style="color: blue;">new</span> Node(t, top);<br /> }<br /><br /> @Override<br /> <span style="color: blue;">public</span> T pop() {<br />  T value = top.value;<br /><br />  <span style="color: blue;">if</span> (!end())<br />   top = top.pre;<br /><br />  <span style="color: blue;">return</span> value;<br /> }<br /><br /> @Override<br /> <span style="color: blue;">public</span> <span style="color: blue;">boolean</span> end() {<br />  <span style="color: blue;">return</span> top.value == <span style="color: blue;">null</span> &amp;&amp; top.pre == <span style="color: blue;">null</span>;<br /> }<br />}</pre></div><br /><div><pre><span style="color: green;">/**<br /> * 定义一个不可变栈<br /> * <br /> * @author xiaomin<br /> * <br /> * @param &lt;T&gt;<br /> */</span><br /><span style="color: blue;">public</span> <span style="color: blue;">class</span> DefaultStack&lt;T <span style="color: blue;">extends</span> Serializable&gt; <span style="color: blue;">implements</span> Stack&lt;T&gt; {<br /><br /> <span style="color: blue;">private</span> <span style="color: blue;">int</span> size;<br /><br /> <span style="color: blue;">private</span> Object[] values;<br /><br /> <span style="color: blue;">private</span> <span style="color: blue;">int</span> curr;<br /><br /> <span style="color: blue;">public</span> DefaultStack(<span style="color: blue;">int</span> size) {<br />  <span style="color: blue;">this</span>.size = size;<br /><br />  curr = -1;<br /><br />  values = <span style="color: blue;">new</span> Object[size];<br /> }<br /><br /> @Override<br /> <span style="color: blue;">public</span> <span style="color: blue;">void</span> push(T t) {<br />  <span style="color: blue;">if</span> ((size - 1) == curr) {<br />   <span style="color: blue;">throw</span> <span style="color: blue;">new</span> UnsupportedOperationException("<span style="color: darkred;">The Stack is full now !</span>");<br />  }<br /><br />  curr++;<br />  values[curr] = t;<br /> }<br /><br /> @SuppressWarnings("<span style="color: darkred;">unchecked</span>")<br /> @Override<br /> <span style="color: blue;">public</span> T pop() {<br />  <span style="color: blue;">if</span> (curr &lt; 0) {<br />   <span style="color: blue;">throw</span> <span style="color: blue;">new</span> UnsupportedOperationException("<span style="color: darkred;">The Stack is empty now !</span>");<br />  }<br /><br />  <span style="color: blue;">return</span> (T) values[curr--];<br /> }<br /><br /> @Override<br /> <span style="color: blue;">public</span> <span style="color: blue;">boolean</span> end() {<br />  <span style="color: blue;">return</span> curr == -1;<br /> }<br />}</pre></div><br /><div><pre><span style="color: green;">/**<br /> * 定义一个容量可变的栈<br /> * <br /> * @author xiaomin<br /> * <br /> * @param &lt;T&gt;<br /> */</span><br /><span style="color: blue;">public</span> <span style="color: blue;">class</span> ListStack&lt;T <span style="color: blue;">extends</span> Serializable&gt; <span style="color: blue;">implements</span> Stack&lt;T&gt; {<br /><br /> <span style="color: blue;">private</span> List&lt;T&gt; list = <span style="color: blue;">null</span>;<br /><br /> <span style="color: blue;">public</span> ListStack() {<br />  list = <span style="color: blue;">new</span> ArrayList&lt;T&gt;();<br /> }<br /><br /> <span style="color: blue;">public</span> ListStack(<span style="color: blue;">int</span> size) {<br />  list = <span style="color: blue;">new</span> ArrayList&lt;T&gt;(size);<br /> }<br /><br /> @Override<br /> <span style="color: blue;">public</span> <span style="color: blue;">void</span> push(T t) {<br />  list.add(t);<br /> }<br /><br /> @Override<br /> <span style="color: blue;">public</span> T pop() {<br />  <span style="color: blue;">if</span> (list.isEmpty()) {<br />   <span style="color: blue;">throw</span> <span style="color: blue;">new</span> EmptyStackException();<br />  }<br /><br />  <span style="color: blue;">return</span> list.remove(list.size() - 1);<br /> }<br /><br /> @Override<br /> <span style="color: blue;">public</span> <span style="color: blue;">boolean</span> end() {<br />  <span style="color: blue;">return</span> list.isEmpty();<br /> }<br />}</pre></div><br />测试代码如下：<br /><div><pre> <span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">void</span> main(String[] args) {<br />  System.out.println("<span style="color: darkred;">link stack ...\n</span>");<br /><br />  Stack&lt;Integer&gt; linkStack = <span style="color: blue;">new</span> LinkStack&lt;Integer&gt;();<br />  <span style="color: blue;">int</span> times = 10;<br /><br />  testMethod(linkStack, times);<br /><br />  System.out.println("<span style="color: darkred;">\ndefault stack ...\n</span>");<br />  Stack&lt;Integer&gt; defaultStack = <span style="color: blue;">new</span> DefaultStack&lt;Integer&gt;(times);<br />  <br />  testMethod(defaultStack, times);<br />  <br />  System.out.println("<span style="color: darkred;">\nlist stack with enouch space...\n</span>");<br />  Stack&lt;Integer&gt; listStack = <span style="color: blue;">new</span> ListStack&lt;Integer&gt;();<br /><br />  testMethod(listStack, times*2);<br /> }<br /><br /> <span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: blue;">void</span> testMethod(Stack&lt;Integer&gt; linkStack, <span style="color: blue;">int</span> times) {<br />  Random random = <span style="color: blue;">new</span> Random(47);<br /><br />  <span style="color: blue;">for</span> (<span style="color: blue;">int</span> i = 0; i &lt; times; i++) {<br />   <span style="color: blue;">int</span> value = i * random.nextInt(times);<br /><br />   System.out.println("<span style="color: darkred;">节点 </span>" + (i + 1) + "<span style="color: darkred;"> : </span>" + value);<br /><br />   linkStack.push(value);<br />  }<br /><br />  System.out.println("<span style="color: darkred;">*********************************</span>");<br /><br />  <span style="color: blue;">int</span> nums = times;<br />  <span style="color: blue;">while</span> (!linkStack.end()) {<br />   System.out.println("<span style="color: darkred;">节点 </span>" + (nums--) + "<span style="color: darkred;"> : </span>" + linkStack.pop());<br />  }<br /> }</pre></div><br />以上代码简单易懂，这里不做过多解释。<img src ="http://www.blogjava.net/yongboy/aggbug/346222.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2010-10-05 11:36 <a href="http://www.blogjava.net/yongboy/archive/2010/10/05/346222.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java war 打包、解压命令</title><link>http://www.blogjava.net/yongboy/archive/2009/09/04/293900.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Fri, 04 Sep 2009 08:39:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2009/09/04/293900.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/293900.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2009/09/04/293900.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/293900.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/293900.html</trackback:ping><description><![CDATA[<p>经常将工程打包成war包，打包如下：</p> <p>// 将当前目录打包成war包</p> <p>jar&nbsp;&nbsp; cvf&nbsp;&nbsp; temp.war&nbsp;&nbsp; */&nbsp; . </p> <p>命令格式：</p> <p>java cvf 打包文件名称 要打包的目录 打包文件保存路径</p> <p>&nbsp;</p> <p>解压自然就是:</p> <p>jar xvf temp.war</p> <p>&nbsp;</p> <p>jar和linux下面的tar命令类似</p><img src ="http://www.blogjava.net/yongboy/aggbug/293900.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2009-09-04 16:39 <a href="http://www.blogjava.net/yongboy/archive/2009/09/04/293900.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>