﻿<?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天空 任我翱翔-随笔分类-Java Language</title><link>http://www.blogjava.net/persister/category/15326.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 17 Sep 2010 07:02:10 GMT</lastBuildDate><pubDate>Fri, 17 Sep 2010 07:02:10 GMT</pubDate><ttl>60</ttl><item><title>1970年1月1日开始计时</title><link>http://www.blogjava.net/persister/archive/2010/02/22/313586.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Mon, 22 Feb 2010 03:07:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2010/02/22/313586.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/313586.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2010/02/22/313586.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/313586.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/313586.html</trackback:ping><description><![CDATA[编程语言和数据库里面经常可以看到，定义的时间是从<font face="Times New Roman">1970</font><font face="宋体">年</font><font face="Times New Roman">1</font><font face="宋体">月</font><font face="Times New Roman">1</font><font face="宋体">日开始，</font>但不知道为啥，于是到网上找找答案。<br />
<br />
比如java中：<br />
<br />
Date&nbsp;date&nbsp;=&nbsp;new&nbsp;Date(0);<br />
System.out.println(date);<br />
<br />
打印出来的结果<font face="Times New Roman">:</font><br />
<br />
Thu&nbsp;Jan&nbsp;01&nbsp;08:00:00&nbsp;CST&nbsp;1970<br />
<br />
也是<font face="Courier New">1970</font><font face="宋体">年</font><font face="Courier New">1</font><font face="宋体">月</font><font face="Courier New">1</font><font face="宋体">日，实际上时分秒是</font><font face="Courier New"><font face="宋体">8</font></font><font face="宋体">点</font><font face="Courier New">0</font><font face="宋体">分</font><font face="Courier New">0</font><font face="宋体">秒</font><font face="Courier New">(</font><font face="宋体">北京时间+8的缘故</font><font face="宋体"></font><font face="Courier New">)</font><font face="宋体">。<br />
</font><br />
最初计算机操作系统是<font face="Times New Roman">32</font><font face="宋体">位，而时间也是用</font><font face="Times New Roman">32</font><font face="宋体">位表示。</font><br />
<br />
System.out.println(Integer.MAX_VALUE);<br />
2147483647<br />
<br />
Integer<font face="宋体">在</font><font face="Courier New">JAVA</font><font face="宋体">内用</font><font face="Courier New">32</font><font face="宋体">位表示，因此</font><font face="Courier New">32</font><font face="宋体">位能表示的最大值是</font>2147483647。另外<font face="Courier New">1</font><font face="宋体">年</font><font face="Courier New">365</font><font face="宋体">天的总秒数是</font>31536000，<br />
<br />
2147483647/31536000&nbsp;=&nbsp;68.1<br />
<br />
因为用<font face="Times New Roman">32</font><font face="宋体">位来表示时间的最大间隔是</font><font face="Times New Roman">68</font><font face="宋体">年，而最早出现的</font><font face="Times New Roman">UNIX</font><font face="宋体">操作系统考虑到计算<br />
机产生的年代和应用的时限综合取了</font><font face="Times New Roman">1970</font><font face="宋体">年</font><font face="Times New Roman">1</font><font face="宋体">月</font><font face="Times New Roman">1</font><font face="宋体">日作为</font><font face="Times New Roman">UNIX&nbsp;TIME</font><font face="宋体">的纪元时间</font><font face="Times New Roman">(</font><font face="宋体">开始<br />
时间</font><font face="Times New Roman">)</font><font face="宋体">，而</font><font face="Times New Roman">java</font><font face="宋体">自然也遵循了这一约束。</font><br />
<br />
至于时间回归的现象相信随着<font face="Times New Roman">64</font><font face="宋体">为操作系统的产生逐渐得到解决，因为用</font><font face="Times New Roman">64</font><font face="宋体">位操作<br />
系统可以表示到</font>292,277,026,596<font face="宋体">年</font>12<font face="宋体">月</font><font face="Times New Roman">4</font><font face="宋体">日</font>15<font face="宋体">时</font><font face="Times New Roman">30</font><font face="宋体">分</font><font face="Times New Roman">08</font><font face="宋体">秒，这个怎么说都够用了，不够的话变成128，256位？</font><font face="宋体">这个时候地球还存在吗？哈哈。<br />
<br />
<br />
</font>
<img src ="http://www.blogjava.net/persister/aggbug/313586.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2010-02-22 11:07 <a href="http://www.blogjava.net/persister/archive/2010/02/22/313586.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多线程设计模式总结</title><link>http://www.blogjava.net/persister/archive/2010/01/31/311388.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Sun, 31 Jan 2010 07:26:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2010/01/31/311388.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/311388.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2010/01/31/311388.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/311388.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/311388.html</trackback:ping><description><![CDATA[Java多线程设计模式，帮助多线程功能提高质量，降低学习成本。主要的Pattern如下：<br />
1.Single Threaded Execution Pattern 多个线程共享一个实例，这样的话，多个线程都<br />
&nbsp; 擅自改动实例的状态，实例会丧失安全性。这种情况可以通过Java的关键词synchronized来解决。如多个人<br />
&nbsp; 通过一个gate时，只能一个个通过，那么可以如下的方式：<br />
&nbsp; public synchronized void pass(String name){<br />
&nbsp;&nbsp; &nbsp;this.name = name;<br />
&nbsp; }<br />
&nbsp; synchronized方法的性能比普通的方法低，所以降低减少使用。<br />
&nbsp; JDK中很多方法是synchronized，可以安全使用，很多为了性能是没有同步。为了提高性能可以考虑使用&nbsp; Immutable Pattern<br />
2.Immutable Pattern 多个线程共享一个实例，但是实例的状态不会改变，可以提供throughput，但必须保证<br />
&nbsp; 不变形（实例的状态不会改变）。需要使用private，final等来支持。<br />
3.Guarded Suspension Pattern 多个线程共享一个实例，这样的话，多个线程都<br />
&nbsp; 擅自改动实例的状态，实例会丧失安全性。当实例的状态不恰当时，就要求线程等待到合适的状态，以&#8220;警戒条&nbsp;&nbsp; 件&#8221;来表示实例的&#8220;适当的状态&#8221;。如果警戒条件一直不成立，线程会永远等待下去，会使程序丧失生命性。Java&nbsp;&nbsp; 中用while循环来测试警戒条件，使用wait方法让线程等待，并使用notify/notifyAll通知警戒条件的改变。<br />
检&nbsp;&nbsp; 验、修改警戒条件是，会使用Single Threaded Execution Pattern。Pattern的例子如下：<br />
&nbsp; public class RequestQueue{<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private final LinkedList queue = new LinkedList();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public synchronized Request getRequest(){<br />
&nbsp;&nbsp; &nbsp;while(queue.size() &lt;= 0){&nbsp;&nbsp; //警戒条件<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try{&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;wait();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }catch(InterruptedException e){}<br />
&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;return (Request)queue.removeFirst();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public synchronized void putRequest(Request request){<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;queue.addLast(request);<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;notifyAll();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp; }<br />
<br />
<br />
&nbsp; 以上使用Queue的客户端和服务器代码里面非常干净，没有多线程的东西，代码复用性很好。<br />
&nbsp; 当警戒条件不成立时想要马上退出，就使用Balking Pattern<br />
4.Balking Pattern 一直等待安全的时机，会使程序的响应性降低。Java语言中，检验警戒条件时要使用if语句<br />
&nbsp; ，当要balk时，可使用return退出方法，或者throw抛出异常。<br />
&nbsp; public class Data {<br />
&nbsp;&nbsp;&nbsp; private String filename;&nbsp;&nbsp;&nbsp; //修改是的名字<br />
&nbsp;&nbsp;&nbsp; private String content;&nbsp;&nbsp;&nbsp;&nbsp; // 资料的内容<br />
&nbsp;&nbsp;&nbsp; private boolean changed;&nbsp;&nbsp;&nbsp; //修改后的内容还没存储的话，值为true<br />
<br />
&nbsp;&nbsp;&nbsp; public Data(String filename, String content) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.filename = filename;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.content = content;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.changed = true;<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; // 修改资料内容<br />
&nbsp;&nbsp;&nbsp; public synchronized void change(String newContent) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; content = newContent;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; changed = true;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp; // 若有资料修改，就存储到挡安里<br />
&nbsp;&nbsp;&nbsp; public synchronized void save() throws IOException {&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!changed) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(Thread.currentThread().getName() + " balks");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return; //没有就退出&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; doSave();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; changed = false;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp; // 实际资料储存到挡案里用的方法<br />
&nbsp;&nbsp;&nbsp; private void doSave() throws IOException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(Thread.currentThread().getName() + " calls doSave, content = " + content);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Writer writer = new FileWriter(filename);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; writer.write(content);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; writer.close();<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
<br />
5.Producer-Consumer Pattern 当Producer参与者与Consumer参与者处理的速度不同时，速度慢的会扯速度快的<br />
&nbsp; 后腿，而降低程序的throughput。解决的办法就是在两者之间，加上中继用的Channel参与者。并让Channel<br />
&nbsp; 参与者存放多条数据，这样就可以缓冲Producer和Consumer之间处理速度的差异。这个模式使用了Guarded <br />
&nbsp; Suspension Pattern。<br />
<br />
&nbsp; public class Table {<br />
&nbsp;&nbsp;&nbsp; private final String[] buffer;<br />
&nbsp;&nbsp;&nbsp; private int tail;&nbsp; /下一个放put的地方 <br />
&nbsp;&nbsp;&nbsp; private int head;&nbsp; //下一个放的take地方<br />
&nbsp;&nbsp;&nbsp; private int count; // buffer内的蛋糕数<br />
&nbsp;&nbsp;&nbsp; public Table(int count) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.buffer = new String[count];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.head = 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.tail = 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.count = 0;<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; // 放置蛋糕<br />
&nbsp;&nbsp;&nbsp; public synchronized void put(String cake) throws InterruptedException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(Thread.currentThread().getName() + " puts " + cake);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (count &gt;= buffer.length) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wait();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buffer[tail] = cake;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tail = (tail + 1) % buffer.length;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; count++;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; notifyAll();<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; // 取得蛋糕<br />
&nbsp;&nbsp;&nbsp; public synchronized String take() throws InterruptedException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (count &lt;= 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wait();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String cake = buffer[head];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; head = (head + 1) % buffer.length;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; count--;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; notifyAll();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(Thread.currentThread().getName() + " takes " + cake);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return cake;<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; }<br />
<br />
6.Read-Write Lock Pattern 多个线程共享一个实例，如进程之间不进行共享胡扯，会丧失安全性。<br />
&nbsp; 但使用Single Threaded Execution Pattern会使程序throughput降低。解决的方法就是将控制reader参与者的&nbsp;&nbsp;&nbsp; 锁定与控制writer参与者的锁定分开，加入ReadWriteLock参与者，以提供两种不同的锁定。<br />
&nbsp;<br />
&nbsp;public final class ReadWriteLock {<br />
&nbsp;&nbsp;&nbsp; private int readingReaders = 0; // (A)...实际正在读取的执行绪数量<br />
&nbsp;&nbsp;&nbsp; private int waitingWriters = 0; // (B)...正在等待写入的执行绪数量<br />
&nbsp;&nbsp;&nbsp; private int writingWriters = 0; // (C)...实际正在写入的执行绪数量<br />
&nbsp;&nbsp;&nbsp; private boolean preferWriter = true; // 写入优先的话，值为true<br />
<br />
&nbsp;&nbsp;&nbsp; public synchronized void readLock() throws InterruptedException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (writingWriters &gt; 0 || (preferWriter &amp;&amp; waitingWriters &gt; 0)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wait();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; readingReaders++;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp; (A)实际正在读取的线程数量加1<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; public synchronized void readUnlock() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; readingReaders--;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp; (A)实际正在读取的线程数量减1<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; preferWriter = true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; notifyAll();<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; public synchronized void writeLock() throws InterruptedException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; waitingWriters++;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // (B)正在等待写入的线程数量加1<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (readingReaders &gt; 0 || writingWriters &gt; 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wait();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } finally {1<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; waitingWriters--;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // (B)正在等待写入的线程数量减1<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; writingWriters++;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp; (C)实际正在写入的线程数量加1<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; public synchronized void writeUnlock() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; writingWriters--;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // (C)实际正在写入的线程数量减<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; preferWriter = false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; notifyAll();<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; }<br />
&nbsp; <br />
&nbsp; public class Data {<br />
&nbsp;&nbsp;&nbsp; private final char[] buffer;<br />
&nbsp;&nbsp;&nbsp; private final ReadWriteLock lock = new ReadWriteLock();<br />
&nbsp;&nbsp;&nbsp; public Data(int size) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.buffer = new char[size];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; buffer.length; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buffer[i] = '*';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; public char[] read() throws InterruptedException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lock.readLock();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return doRead();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } finally {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lock.readUnlock();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; public void write(char c) throws InterruptedException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lock.writeLock();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; doWrite(c);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } finally {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lock.writeUnlock();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; private char[] doRead() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char[] newbuf = new char[buffer.length];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; buffer.length; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; newbuf[i] = buffer[i];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; slowly();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return newbuf;<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; private void doWrite(char c) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; buffer.length; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buffer[i] = c;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; slowly();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; private void slowly() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep(50);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (InterruptedException e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; }<br />
<br />
7.Thread-Per-Message Pattern&nbsp; 在方法的属性处理完成之前，控制权不会从Host参与者退出。如果方法的处理<br />
&nbsp; 属性很话费时间，程序的响应性能会降低。解决的方式就在Host的参与者里，启动新的线程，并且将该方法应&nbsp;&nbsp;&nbsp; 该进行的工作交给这个心的线程，这样Client参与者的线程可以继续执行下一个操作，这样做，不用更改&nbsp;&nbsp;&nbsp; Client参与者的程序代码，并能提高程序的响应性。想节省启动线程所花费的时间，可以使用Worker Thread&nbsp;&nbsp;&nbsp; Pattern。<br />
&nbsp; public class Host {<br />
&nbsp;&nbsp;&nbsp; private final Helper helper = new Helper();<br />
&nbsp;&nbsp;&nbsp; public void request(final int count, final char c) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("&nbsp;&nbsp;&nbsp; request(" + count + ", " + c + ") BEGIN");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new Thread() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void run() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; helper.handle(count, c);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }.start();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("&nbsp;&nbsp;&nbsp; request(" + count + ", " + c + ") END");<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; }<br />
<br />
8.Worker Thread Pattern 如果方法的处理属性很花时间，程序的响应性会降低。为了提供响应性，而启动新<br />
&nbsp; 的线程来处理方法时，启动线程所花的时间又会降低throughput。另外当送出的请求太多时，会启动<br />
&nbsp; 过多的线程，这会使承载量变差。<br />
&nbsp; public class Channel {<br />
&nbsp;&nbsp;&nbsp; private static final int MAX_REQUEST = 100;<br />
&nbsp;&nbsp;&nbsp; private final Request[] requestQueue;<br />
&nbsp;&nbsp;&nbsp; private int tail;&nbsp; // 下一个putRequest的地方<br />
&nbsp;&nbsp;&nbsp; private int head;&nbsp; // 下一个takeRequest的地方<br />
&nbsp;&nbsp;&nbsp; private int count; // Request的数量<br />
<br />
&nbsp;&nbsp;&nbsp; private final WorkerThread[] threadPool;<br />
<br />
&nbsp;&nbsp;&nbsp; public Channel(int threads) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.requestQueue = new Request[MAX_REQUEST];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.head = 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.tail = 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.count = 0;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; threadPool = new WorkerThread[threads];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; threadPool.length; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; threadPool[i] = new WorkerThread("Worker-" + i, this);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; public void startWorkers() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; threadPool.length; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; threadPool[i].start();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; public synchronized void putRequest(Request request) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (count &gt;= requestQueue.length) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wait();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (InterruptedException e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; requestQueue[tail] = request;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tail = (tail + 1) % requestQueue.length;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; count++;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; notifyAll();<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; public synchronized Request takeRequest() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (count &lt;= 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wait();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (InterruptedException e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Request request = requestQueue[head];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; head = (head + 1) % requestQueue.length;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; count--;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; notifyAll();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return request;<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; }<br />
<br />
9.Future Pattern 当Client会将工作委托给其他线程，而Client参与者希望得到处理的结果。将工作委托给<br />
&nbsp; 别人时，如果又等待执行结果，会使响应性降低。<br />
&nbsp; public class FutureData implements Data {<br />
&nbsp;&nbsp;&nbsp; private RealData realdata = null;<br />
&nbsp;&nbsp;&nbsp; private boolean ready = false;<br />
&nbsp;&nbsp;&nbsp; public synchronized void setRealData(RealData realdata) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ready) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;&nbsp;&nbsp;&nbsp;&nbsp; // balk<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.realdata = realdata;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.ready = true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; notifyAll();<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; public synchronized String getContent() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (!ready) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wait();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (InterruptedException e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return realdata.getContent();<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; }<br />
<br />
<br />
附多线程程序的评价标准<br />
1、安全性——不损坏对象 对象损坏是指对象的状态不符合设计师的原意，通常是获取对象的状态值并非预期值。<br />
2、生存性——进行必要的处理 也许不是现在，但是一定会进行必要的处理，如果程序安全了，但是有些必要的处理得不到操作，那么这个多线程程序也是不合格的。<br />
3、复用性——可再利用类 写多线程程序，如果能够将多线程的共享和互斥结构隐藏在类里面，这就是一个高度可复印的程序。<br />
4、性能——能快速大量处理 主要表现在吞吐量（Throughput）即一定时间内能完成的处理量，能完成的处理量越多，表示数据吞吐量越大；容量（Capacity）指可同时处理的数量；响应性（Responsiveness）指从发出请求到收到响应的时间，时间越短，响应性越高。<br />
5、伸缩性（Scalability）等<br />
<br />
前两个是必要条件，后面几个是程序质量的描述<br />
 <img src ="http://www.blogjava.net/persister/aggbug/311388.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2010-01-31 15:26 <a href="http://www.blogjava.net/persister/archive/2010/01/31/311388.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java NIO学习笔记二</title><link>http://www.blogjava.net/persister/archive/2010/01/19/310087.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Tue, 19 Jan 2010 07:44:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2010/01/19/310087.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/310087.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2010/01/19/310087.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/310087.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/310087.html</trackback:ping><description><![CDATA[Java NIO最吸引人的地方是提供了非阻塞的IO，可以方便的编写出高性能的服务器。NIO里面包括Buffer，Channel和Nonblocking IO。如下几篇文章可以参考：<br />
<a id="Results_rprSelectionList_ctl09_LinkTitle" class="titlelink" href="http://www.diybl.com/course/3_program/java/javashl/20081123/152302.html">http://www.diybl.com/course/3_program/java/javashl/20081123/152302.html</a><br />
<a id="Results_rprSelectionList_ctl08_Hyperlink1" class="titlelink" href="http://www.javaeye.com/topic/40489">http://www.javaeye.com/topic/40489</a><br />
<a id="Results_rprSelectionList_ctl07_LinkTitle" class="titlelink" href="http://dengminhui.javaeye.com/blog/500876">http://dengminhui.javaeye.com/blog/500876</a><br />
<a id="Results_rprSelectionList_ctl06_Hyperlink1" class="titlelink" href="http://blog.csdn.net/lcllcl987/archive/2007/04/16/1566114.aspx">http://blog.csdn.net/lcllcl987/archive/2007/04/16/1566114.aspx</a><br />
<br />
具体可以看O'Reilly.Java.I.O.2nd.Edition.chm，写得非常的详细。<br />
<br />
Apahce提供了Java NIO封装的框架Mina。现在发展到2.0，可以用来学习高性能网络编程。<br />
<br />
<img src ="http://www.blogjava.net/persister/aggbug/310087.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2010-01-19 15:44 <a href="http://www.blogjava.net/persister/archive/2010/01/19/310087.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多线程访问数据库导致内存泄露的优化过程</title><link>http://www.blogjava.net/persister/archive/2010/01/14/309530.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Thu, 14 Jan 2010 13:11:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2010/01/14/309530.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/309530.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2010/01/14/309530.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/309530.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/309530.html</trackback:ping><description><![CDATA[1、这家公司有一个数据库代理程序，用于数据库服务器的代理，游戏服务器执行sql指令，DBAgent接受此指令，执行一些组织后，调用JDBC执行数据库操作，然后将结果返回。<br />
<br />
2、发生的问题：内存一直升高，处理客户端请求的线程并不多（高峰期大概300左右吧），数据库上的连接数也不多（100的样子）。运行5-6天，基本上内存就用完了，而且得不到数据库的连接。他们非常急，我就试着接下这个项目。<br />
<br />
3、接到这个优化项目，查看了他们的部分代码。发现连接池写得有些问题，得不到数据库连接后wait，但是不会接到任何有效的notify，也就是说只要一等待就会超时。还有其他的问题，一开始我以为是这个问题，修改后让他们去跑，结果还是一样，内存上去后一直下不来，最后崩溃。<br />
<br />
4、通过这个发现就是内存泄露了。一开始用jprofiler测试，发现内存上去后就Out of memory了，而且hashmap和long[]的对象非常多一直下不去。但是找不到这些对象是怎么产生的。折磨了我好几天，还请教了很多人，都得不到答案。后来发现是java启动参数中内存参数设置的太低了，本来需要100多M的内存，你就设置给16M，不崩溃才怪呢。于是改成了128M。结果内存上去之后，到达一个峰值就下来了，然后震荡，但一直就没有上去。那程序没有泄露？可是生产上怎么泄露了呢？<br />
<br />
5、就在我基本上要放弃的时候，我想到了测试环境可能真实环境不同，有必要看一下他们生产服务器上虚拟机的运行情况。记得Java有自带的工具查询java虚拟机运行情况的。jmap这个工具可以查看jvm中运行实例的个数以及实例的类名。让他们的人用了下这个工具，将结果发给我了，我一看，吓了一大跳。排在第一位的是int[]，竟然达到了1G。最有问题的是com.mysql.jdbc.PreparedStatement对象，达到了6万多。com.mysql.jdbc.ResultSetImpl和java.util.HashMap$Entry[]也达到了6万多。不用说，肯定是PreparedStatement没有关闭。<br />
<br />
6、查看源代码，发现PreparedStatement对象都在finally块中关闭了，怎么会泄露呢？找了1个小时没有找到，就去洗澡了。在洗澡的时候突然想到，里面有一个for循环，PreparedStatement对象可能被赋值N次，那前面的N-1次不就没有关闭啊，对，找到答案了。赶紧擦干身子出来找到那段代码：<br />
<br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080;">&nbsp;1</span>&nbsp;<span style="color: #000000;">&nbsp;String[]&nbsp;valuesArray&nbsp;=&nbsp;value.split(";");<br />
</span><span style="color: #008080;">&nbsp;2</span>&nbsp;<span style="color: #000000;">&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0&nbsp;;i&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">&nbsp;valuesArray</span><span style="color: #ff0000;">.length;i++){<br />
</span><span style="color: #008080;">&nbsp;3</span>&nbsp;<span style="color: #ff0000;"><br />
</span><span style="color: #008080;">&nbsp;4</span>&nbsp;<span style="color: #ff0000;">String[]&nbsp;valueArray&nbsp;</span><span style="color: #0000ff;">=&nbsp;valuesArray[i].split(",");</span><span style="color: #ff0000;"><br />
</span><span style="color: #008080;">10</span>&nbsp;<span style="color: #ff0000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ps&nbsp;</span><span style="color: #0000ff;">=&nbsp;conn.prepareStatement(sqlbean.getSql());<br />
</span><span style="color: #008080;">11</span>&nbsp;<span style="color: #0000ff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #ff0000;">for(int&nbsp;k&nbsp;</span><span style="color: #0000ff;">=&nbsp;0;k&nbsp;</span><span style="color: #ff0000;">&lt;valueArray.length;k++){<br />
</span><span style="color: #008080;">12</span>&nbsp;<span style="color: #ff0000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if("s".equalsIgnoreCase(paraTypeArray[k])){<br />
</span><span style="color: #008080;">13</span>&nbsp;<span style="color: #ff0000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ps.setString(k+1,valueArray[k]);<br />
</span><span style="color: #008080;">14</span>&nbsp;<span style="color: #ff0000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}else&nbsp;if("i".equalsIgnoreCase(paraTypeArray[k])){<br />
</span><span style="color: #008080;">15</span>&nbsp;<span style="color: #ff0000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ps.setInt(k+1,Integer.parseInt(valueArray[k]));<br />
</span><span style="color: #008080;">16</span>&nbsp;<span style="color: #ff0000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</span><span style="color: #008080;">17</span>&nbsp;<span style="color: #ff0000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</span><span style="color: #008080;">18</span>&nbsp;<span style="color: #ff0000;"><br />
</span><span style="color: #008080;">19</span>&nbsp;<span style="color: #ff0000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rsString&nbsp;</span><span style="color: #0000ff;">=&nbsp;""</span><span style="color: #ff0000;">&nbsp;+&nbsp;ps.executeUpdate();<br />
</span><span style="color: #008080;">20</span>&nbsp;<span style="color: #ff0000;"><br />
</span><span style="color: #008080;">21</span>&nbsp;<span style="color: #ff0000;">}</span></div>
<br />
<br />
确实如此，循环的N-1个PreparedStatement对象没有关闭，导致了泄漏。解决办法就是将<br />
<span style="color: #ff0000;">ps&nbsp;</span><span style="color: #0000ff;">=&nbsp;conn.prepareStatement(sqlbean.getSql());<br />
<br />
移到for循环的外面，这样就没有问题了。不过从这段代码也可以看出，写得也是在是烂，这个干吗放到<br />
循环的里面呢，本身从语言上来说就有问题。管它呢，解决问题就行了，呵呵。</span><br />
几乎兴奋了一个晚上。第二天找他们的人一说，他们说是循环N次的，不只是一个值。问题不就解决了？Great。<br />
<br />
7、让他们去测试运行吧。运行第一天的晚上九点（这是高峰期）以后，内存非常平稳。问题彻底解决了。<br />
<br />
总结这次的优化项目：<br />
对Java虚拟机的认识提高了。对java性能测试工具（JProfiler）更加熟练了，可以和eclipse集成呢，非常方便。<br />
&nbsp;&nbsp; <br />
 <img src ="http://www.blogjava.net/persister/aggbug/309530.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2010-01-14 21:11 <a href="http://www.blogjava.net/persister/archive/2010/01/14/309530.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java多线程设计模式:wait/notify机制</title><link>http://www.blogjava.net/persister/archive/2009/12/03/304620.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Thu, 03 Dec 2009 06:45:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/12/03/304620.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/304620.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/12/03/304620.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/304620.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/304620.html</trackback:ping><description><![CDATA[通常，多线程之间需要协调工作。例如，浏览器的一个显示图片的线程displayThread想要执行显示图片的任务，必须等待下载线程
downloadThread将该图片下载完毕。<br />
如果图片还没有下载完，displayThread能暂停，当downloadThread完成了任务
后，再通知displayThread&#8220;图片准备完毕，能显示了&#8221;，这时，displayThread继续执行。　　<br />
以上逻辑简单的说就是：如果条件不满足，则等待。<br />
当条件满足时，等待该条件的线程将被唤醒。<br />
在Java中，这个机制的实现依赖于wait/notify。等待机制和锁机制是密切关联的。<br />
例如：　　<br />
<br />
<br />
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 128, 128);">1</span>&nbsp;<span style="color: rgb(0, 0, 255);">synchronized</span><span style="color: rgb(0, 0, 0);">(obj)<br />
</span><span style="color: rgb(0, 128, 128);">2</span>&nbsp;<span style="color: rgb(0, 0, 0);">{　　<br />
</span><span style="color: rgb(0, 128, 128);">3</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">while</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">!</span><span style="color: rgb(0, 0, 0);">condition)<br />
</span><span style="color: rgb(0, 128, 128);">4</span>&nbsp;<span style="color: rgb(0, 0, 0);">{<br />
</span><span style="color: rgb(0, 128, 128);">5</span>&nbsp;<span style="color: rgb(0, 0, 0);">　　obj.wait();　　<br />
</span><span style="color: rgb(0, 128, 128);">6</span>&nbsp;<span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 128, 128);">7</span>&nbsp;<span style="color: rgb(0, 0, 0);">}　　<br />
</span><span style="color: rgb(0, 128, 128);">8</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;obj.doSomething();　　<br />
</span><span style="color: rgb(0, 128, 128);">9</span>&nbsp;<span style="color: rgb(0, 0, 0);">}　</span></div>
当线程A获得了obj锁后，发现条件condition不满足，无法继续下一处理，于是线程A就wait()。　　在另一线程B中，如果B更改了某些条件，使得线程A的condition条件满足了，就能唤醒线程A：<br />
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 128, 128);">1</span>&nbsp;<span style="color: rgb(0, 0, 255);">synchronized</span><span style="color: rgb(0, 0, 0);">(obj)<br />
</span><span style="color: rgb(0, 128, 128);">2</span>&nbsp;<span style="color: rgb(0, 0, 0);">{　　<br />
</span><span style="color: rgb(0, 128, 128);">3</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;condition&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">true</span><span style="color: rgb(0, 0, 0);">;　　<br />
</span><span style="color: rgb(0, 128, 128);">4</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;obj.notify();　　<br />
</span><span style="color: rgb(0, 128, 128);">5</span>&nbsp;<span style="color: rgb(0, 0, 0);">}　</span></div>
<br />
<br />
需要注意的概念是：　　<br />
# 调用obj的wait(), notify()方法前，必须获得obj锁，也就是必须写在synchronized(obj) {...} 代码段内。　　<br />
<br />
# 调用obj.wait()后，线程A就释放了obj的锁，否则线程B无法获得obj锁，也就无法在synchronized(obj) {...} 代码段内唤醒A。　　<br />
<br />
# 当obj.wait()方法返回后，线程A需要再次获得obj锁，才能继续执行。　　<br />
# 如果A1,A2,A3都在obj.wait()，则B调用obj.notify()只能唤醒A1,A2,A3中的一个（具体哪一个由JVM决定）。　　<br />
# obj.notifyAll()则能全部唤醒A1,A2,A3，不过要继续执行obj.wait()的下一条语句，必须获得obj锁，因此，A1,A2,A3只有一个有机会获得锁继续执行，例如A1，其余的需要等待A1释放obj锁之后才能继续执行。　　<br />
# 当B调用obj.notify/notifyAll的时候，B正持有obj锁，因此，A1,A2,A3虽被唤醒，不过仍无法获得obj锁。直到B退出synchronized块，释放obj锁后，A1,A2,A3中的一个才有机会获得锁继续执行。
<img src ="http://www.blogjava.net/persister/aggbug/304620.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-12-03 14:45 <a href="http://www.blogjava.net/persister/archive/2009/12/03/304620.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>James配置邮箱服务器</title><link>http://www.blogjava.net/persister/archive/2009/11/15/302418.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Sun, 15 Nov 2009 07:32:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/11/15/302418.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/302418.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/11/15/302418.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/302418.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/302418.html</trackback:ping><description><![CDATA[按照网上说的配置好了，具体参考<a id="Results_rprSelectionList_ctl15_LinkTitle" class="titlelink" href="http://blog.csdn.net/ejbcreate/archive/2009/10/22/4712681.aspx">http://blog.csdn.net/ejbcreate/archive/2009/10/22/4712681.aspx</a>
。可是用公司的outlook总是不成功，只能收邮件，不能往其他邮箱发送邮件<br />
后来改成foxmail6，结果就可以了。尝试一下不是用smtp authentication，结果也能发送，吓了一跳<br />
岂不是邮箱服务器变成open relay了，到网上一查，说foxmail4以后的版本默认就加上认证了<br />
也即是说你没选认证的话也会帮你加上，所以不用担心了。<br />
对James邮箱服务器学的还不深，有时候可以研究一下，学学pop和smtp等协议。<br />
<br />
<img src ="http://www.blogjava.net/persister/aggbug/302418.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-11-15 15:32 <a href="http://www.blogjava.net/persister/archive/2009/11/15/302418.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在jsp中怎么实现登录后，自动跳转到登录前正浏览的页面</title><link>http://www.blogjava.net/persister/archive/2009/10/19/298839.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Mon, 19 Oct 2009 05:58:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/10/19/298839.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/298839.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/10/19/298839.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/298839.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/298839.html</trackback:ping><description><![CDATA[<pre>在jsp中怎么实现登录后，自动跳转到登录前正浏览的页面？就像csdn的一样，<br />
不管你从哪能个页面登录，成功登录后会自动跳转回那个页面。<br />
解决方法一：<br />
登录处理后，返回如下内容：&nbsp;&nbsp; <br />
</pre>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><span style="color: #000000;">
</span><span style="color: #008080;">&nbsp;2</span>&nbsp;<span style="color: #000000;">PrintWriter&nbsp;out&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;response.getWriter();<br />
</span><span style="color: #008080;">&nbsp;3</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;4</span>&nbsp;<span style="color: #000000;">out</span><span style="color: #000000;">.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">&lt;!DOCTYPE&nbsp;HTML&nbsp;PUBLIC&nbsp;</span><span style="color: #000000;">""</span><span style="color: #000000;">-//W3C//DTD&nbsp;HTML&nbsp;4.01&nbsp;Transitional//EN</span><span style="color: #000000;">""</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
</span><span style="color: #008080;">&nbsp;7</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;8</span>&nbsp;<span style="color: #000000;">out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">&lt;HTML&gt;</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
</span><span style="color: #008080;">&nbsp;9</span> <span style="color: #000000;"><br />
</span><span style="color: #008080;">11</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">12</span>&nbsp;<span style="color: #000000;">out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;&nbsp;&lt;BODY&gt;</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
</span><span style="color: #008080;">13</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">16</span>&nbsp;<span style="color: #000000;">out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">&lt;script&gt;history.go(-1);history.go(0);&lt;/script&gt;</span><span style="color: #000000;">"</span><span style="color: #000000;">);</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">19</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">20</span>&nbsp;<span style="color: #000000;">out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;&nbsp;&lt;/BODY&gt;</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
</span><span style="color: #008080;">21</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">22</span>&nbsp;<span style="color: #000000;">out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">&lt;/HTML&gt;</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
</span><span style="color: #008080;">23</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">24</span>&nbsp;<span style="color: #000000;">out.flush();<br />
</span><span style="color: #008080;">25</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">26</span>&nbsp;<span style="color: #000000;">out.close();<br />
</span><span style="color: #008080;">27</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">28</span>&nbsp;<span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">;&nbsp;<br />
</span><span style="color: #008080;">29</span>&nbsp;</div>
<pre>解决方法二：&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008080;"><br />
<br />
1</span>&nbsp;<span style="color: #000000;">String&nbsp;referer&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;req.getHeader(</span><span style="color: #000000;">"</span><span style="color: #000000;">Referer</span><span style="color: #000000;">"</span>);<br />
</pre>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><span style="color: #000000;">
</span><span style="color: #008080;">2</span> <span style="color: #000000;">resp.sendRedirect(referer);<br />
</span><span style="color: #008080;">3</span> <span style="color: #0000ff;">return</span><span style="color: #000000;">;<br />
</span><span style="color: #008080;">4</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">5</span>&nbsp;</div>
<pre>上面两种方法不可取是因为，如果用户登录失败，再次登录的话就会出现登录后返回到登录的错误。<br />
<br />
第三种：把你要在跳转时需要保存的信息存放在session变量中，登录后清除这个session。可行。<br />
需要登录操作的页面上面添加：<br />
</pre>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080;">1</span>&nbsp;<span style="color: #000000;">&lt;%</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">2</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(session.getAttribute(</span><span style="color: #000000;">"</span><span style="color: #000000;">party</span><span style="color: #000000;">"</span><span style="color: #000000;">)</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">){<br />
</span><span style="color: #008080;">3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(</span><span style="color: #0000ff;">null</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;request.getQueryString())<br />
</span><span style="color: #008080;">4</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session.setAttribute(</span><span style="color: #000000;">"</span><span style="color: #000000;">redirectUrl</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;request.getRequestURL().append(</span><span style="color: #000000;">"</span><span style="color: #000000;">?</span><span style="color: #000000;">"</span><span style="color: #000000;">).append(request.getQueryString()).toString());<br />
</span><span style="color: #008080;">5</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">6</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session.setAttribute(</span><span style="color: #000000;">"</span><span style="color: #000000;">redirectUrl</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;request.getRequestURL().toString());<br />
</span><span style="color: #008080;">7</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.sendRedirect(request.getContextPath()&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">/loginto</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
</span><span style="color: #008080;">8</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</span><span style="color: #008080;">9</span>&nbsp;<span style="color: #000000;">%&gt;</span></div>
<pre>在登录处理页面：<br />
<br />
</pre>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080;">1</span>&nbsp;<span style="color: #000000;">String&nbsp;redirectUrl&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;(String)req.getSession().getAttribute(</span><span style="color: #000000;">"</span><span style="color: #000000;">redirectUrl</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
</span><span style="color: #008080;">2</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(StringUtils.isValid(redirectUrl)){<br />
</span><span style="color: #008080;">3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;req.getSession().removeAttribute(</span><span style="color: #000000;">"</span><span style="color: #000000;">redirectUrl</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
</span><span style="color: #008080;">4</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;resp.sendRedirect(redirectUrl);<br />
</span><span style="color: #008080;">5</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
<pre>
第四种方法：写一个servlet会话判断类，如果在线就继续执行，不在线则提示登录。所有的需要在线操作的
servlet都集成此类，这样就不需要上面那么在每个页面写上这些代码了，可以集中控制。这种方式比较完整。<br />
<br />
</pre>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><span style="color: #000000;">HttpSession&nbsp;session&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;request.getSession();<br />
<br />
</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(session.getAttribute(</span><span style="color: #000000;">"</span><span style="color: #000000;">person</span><span style="color: #000000;">"</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">)&nbsp;<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">null</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;request.getQueryString())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session.setAttribute(</span><span style="color: #000000;">"</span><span style="color: #000000;">redirectUrl</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;request.getRequestURL().append(</span><span style="color: #000000;">"</span><span style="color: #000000;">?</span><span style="color: #000000;">"</span><span style="color: #000000;">).append(request.getQueryString()).toString());<br />
&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff;">else</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session.setAttribute(</span><span style="color: #000000;">"</span><span style="color: #000000;">redirectUrl</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;request.getRequestURL()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.toString());<br />
&nbsp;&nbsp;&nbsp;&nbsp; response.sendRedirect(request.getContextPath()&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">/login.jsp</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">;<br />
&nbsp;}<br />
<br />
</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;process(config,&nbsp;request,&nbsp;response);</span></div>
<pre><br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
</pre>
<img src ="http://www.blogjava.net/persister/aggbug/298839.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-10-19 13:58 <a href="http://www.blogjava.net/persister/archive/2009/10/19/298839.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java乱码问题网上总结，非常不错</title><link>http://www.blogjava.net/persister/archive/2009/10/16/298512.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Fri, 16 Oct 2009 02:29:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/10/16/298512.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/298512.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/10/16/298512.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/298512.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/298512.html</trackback:ping><description><![CDATA[Java开发中经常会遇到乱码问题，下面是几个在开发中应该注意的问题：<br />
<br />
1.尽量使用统一的编码，如果你是重头开发一个系统，特别是Java开发的，所有的文件包括js和css，数据库连接都是用UTF-8进行编码。<br />
<br />
2.添加Filter进行编码设定，这个是我们经常用的。<br />
<br />
3.尽早统一开发环境，早点模拟真实环境测试，平台可能造成乱码问题。<br />
<br />
二、乱码发生的情况和应对措施<br />
1.开发环境乱码<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 由于Java默认使用UTF-8编码，而且网上很多人都建议Struts开发的时候应尽量选用UTF-8做为默认编码，而非GBK。IDE使用Eclipse，在第一次使用Eclipse的时候应将default text editor改为UTF-8编码。<br />
<br />
2.POST请求的过滤<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这个是最基本的了，每个Servlet系统基本都会用到这个东西。不过只对POST请求有效，这个挺关键的。使用SetCharacterEncodingFilter，这个很基础的一套过滤器，将所有来自页面的POST请求全部过滤为UTF-8编码。<br />
<br />
3. JSP ,HTML页面乱码<br />
&nbsp;&nbsp;&nbsp;&nbsp; 将JSP页面全部改为charset=UTF-8，这样可以保证与后台交互的时候都是UTF-8编码，一般应用做了以上工作。<br />
<br />
就基本可以应付了。<br />
<br />
4.资源文件中汉字转化UTF-8字符问题<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 国际化问题，在使用资源文件的时候，由于中文在properties文件中无法被程序所识别，需要将其进行转码，我在资源文件下面制作了一个很简单的 bat文件，每次修改资源文件的时候都是在一个临时文件中修改，然后执行这个bat文件，<br />
set path=%path%;%JAVA_HOME%/bin/,native2ascii -encoding UTF-8 ApplicationResources_bk.txt &gt; <br />
<br />
ApplicationResources_zh.properties<br />
<br />
5. GET请求乱码<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果在本项目中采用了get方式提交请求并附加参数，结果导致编码乱码，原因是Tomcat默认请求编码是ISO8859，需要在Tomcat的配置文件 server.xml添加一个参数，URIEncoding=&#8221;UTF-8&#8221;,这样请求中附件的参数就会以UTF-8来进行编码。这个方法不错，将ajax中get方式请求中的中文全处理了。<br />
<br />
6.Ajax请求乱码<br />
&nbsp;&nbsp;&nbsp; 使用Ajax，JS 也是默认使用ISO8859编码，所以在进行请求时遇到中文参数需要进行编码，如：var url = <br />
<br />
"GetSelectListAction.do?queryData=subTrade" + "&amp;queryId=" + encodeURI(obj.value) + "&amp;r=" + <br />
<br />
Math.random(); &nbsp;<br />
&nbsp;&nbsp;&nbsp; 这里有两个地方需要注意：第一个地方是encodeURI()，方法，可以将参数进行转码，默认是转化为UTF-8，如果需要转为其他码制，需要在方法中添加第二个参数。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 第二个地方是Math.random()，由于Ajax有缓存机制，在接受请求的时候第一时间先判断该请求的地址是否被访问过，如果被访问过则 直接使用缓存中的内容返回，这个东西很讨厌，客户在访问过一次出错后以后每次出现的都是这个错误，所以在请求中给其增加一个时间戳，只要可以随机生成一个 不同的字串就可以，保证Ajax每次都去访问服务器。<br />
<br />
7. GET方法的另一个乱码问题<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在项目即将交工的时候突然又出现乱码问题，发现对于超长的汉字做为参数传递仍然会出现乱码问题，解决方法是采用java.net.URLEncoder的 Encode方法强制转码，缺点是会使JSP页面代码相当的长，但是目前还没有其他好的解决办法，我想最好的办法就是不用中文做为参数传递：<br />
<br />
&lt;a href="TestAction.do?name=&lt;%= java.net.URLEncoder.encode("你好","UTF-8")%&gt;<br />
<br />
<img src ="http://www.blogjava.net/persister/aggbug/298512.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-10-16 10:29 <a href="http://www.blogjava.net/persister/archive/2009/10/16/298512.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>apache+tomcat 负载均衡安装配置</title><link>http://www.blogjava.net/persister/archive/2009/10/14/298279.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Wed, 14 Oct 2009 12:28:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/10/14/298279.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/298279.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/10/14/298279.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/298279.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/298279.html</trackback:ping><description><![CDATA[1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 操作系统 <br />
RedHat Linux<br />
2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 所需软件 <br />
Apache 2.2.14&nbsp; 下载地址 <br />
http://apache.freelamp.com/httpd/httpd-2.2.14.tar.gz<br />
Tomcat5.5.28&nbsp;&nbsp;&nbsp; 下载地址 <br />
http://tomcat.apache.org/download-55.cgi<br />
JK&nbsp; 下载地址<br />
http://apache.etoak.com/tomcat/tomcat-connectors<br />
&nbsp;文件：tomcat-connectors-1.2.28-src.tar.gz<br />
<br />
Jdk 1_5_0_04&nbsp;&nbsp; 下载地址 <br />
&nbsp;&nbsp;&nbsp; http://java.sun.com/j2se/1.5.0/download.jsp <br />
<br />
备注：下载时将所需软件包文件保存在/opt目录下 <br />
3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 安装步骤 <br />
<br />
A 安装JDK<br />
# cd /opt/<br />
# chmod +x jdk-1_5_0_04-linux-i586-rpm.bin<br />
# ./jdk-1.5.0_04-linux-i586-rpm.bin<br />
# cd /usr/java/<br />
# ln -s /usr/java/jdk-1_5_0_04 /opt/java<br />
# vi /etc/profile<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #添加如下内容 <br />
<br />
export JAVA_HOME=/opt/java/<br />
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar<br />
export PATH=.:$JAVA_HOME/bin:$PATH<br />
<br />
<br />
B 安装Apache<br />
<br />
# cd /opt/<br />
# tar xvfz httpd-2.0.54.tar.gz<br />
# cd httpd-2.0.54<br />
#./configure --prefix=/opt/apache --enable-module=so<br />
# make<br />
# make install<br />
# cd /opt/apache/conf<br />
# vi ./httpd.conf<br />
<br />
将Listen 80 修改为Listen &lt;Your IP&gt;:80 IP到时候就是自己机器的IP地址，否则<br />
其他机器没法访问你。<br />
<br />
将ServerName 修改为ServerName &lt;HOST-NAME&gt; ，这个地方直接127.0.0.1即可。集群的时候会读httpd-vhost.conf<br />
<br />
下面是一个配置有关的问题：<br />
<br />
修改serverName，重装apache后问题依旧，最后发现host配置不正确，<br />
<br />
httpd.conf 中serverName 为www.zudar.com<br />
<br />
host 中 127.0.0.1 www.zudar.com<br />
<br />
改为 192.168.100.38&nbsp; www.zudar.com<br />
<br />
后正确启动<br />
<br />
问题是由于 ip 地址 与 域名没有正确匹配引起<br />
<br />
也就是说host中一点要配置好ip与serverName<br />
<br />
hostname与/etc/hosts的关系<br />
<br />
很过人一提到更改hostname首先就想到修改/etc/hosts文件，认为hostname的配置文件就是/etc/hosts。其实不是的。<br />
<br />
hosts文件的作用相当如DNS，提供IP地址到hostname的对应。早期的互联网计算机少，单机hosts文件里足够存放所有联网计算机。不过随着互联网的发展，这就远远不够了。于是就出现了分布式的DNS系统。由DNS服务器来提供类似的IP地址到域名的对应。具体可以man hosts。<br />
<br />
Linux系统在向DNS服务器发出域名解析请求之前会查询/etc/hosts文件，如果里面有相应的记录，就会使用hosts里面的记录。/etc/hosts文件通常里面包含这一条记录<br />
127.0.0.1&nbsp;&nbsp;&nbsp; localhost.localdomain&nbsp;&nbsp; localhost<br />
<br />
hosts文件格式是一行一条记录，分别是IP地址 hostname aliases，三者用空白字符分隔，aliases可选。<br />
<br />
127.0.0.1到localhost这一条建议不要修改，因为很多应用程序会用到这个，比如sendmail，修改之后这些程序可能就无法正常运行。<br />
<br />
修改hostname后，如果想要在本机上用newhostname来访问，就必须在/etc/hosts文件里添加一条newhostname的记录。比如我的eth0的IP是192.168.1.61，我将hosts文件修改如下：<br />
#hostname blog.infernor.net<br />
# cat /etc/hosts<br />
127.0.0.1&nbsp; localhost.localdomain localhost<br />
192.168.1.61&nbsp;&nbsp;&nbsp; blog.infernor.net&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; blog<br />
<br />
这样，我就可以通过blog或者blog.infernor.net来访问本机。<br />
<br />
<br />
<br />
<br />
在DirectoryIndex中添加 index.jsp<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # cd /opt/apache/bin/<br />
<br />
# ./apachectl configtest<br />
<br />
若显示Syntax ok则表明安装成功 <br />
<br />
#./apachectl start<br />
<br />
启动apache服务，访问本机80端口，查看端口是否正常 <br />
<br />
# ./apachectl stop<br />
<br />
关闭服务 <br />
<br />
备注：prefix定义apache的安装路径 <br />
<br />
C 安装Tomcat<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # cd /opt/<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # tar xvfz jakarta-tomcat-5.5.9.tar.gz<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # ln &#8211;s /opt/jakarta-tomcat-5.5.9　/opt/tomcat<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # vi /opt/tomcat/bin/catalina.sh<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JAVA_HOME=/opt/java <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 启动服务后，访问本机8080端口，查看端口是否正常 <br />
<br />
# /opt/tomcat/bin/startup.sh /startup.bat&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 关闭服务 <br />
<br />
# /opt/tomcat/bin/shutdown.sh /shutdown.bat<br />
<br />
修改各个tomcat的端口（如果两台机器是在不同的主机上，端口可以不动，显然）<br />
tomcat1/conf/server.xml<br />
&lt;Server port="8005" shutdown="SHUTDOWN" debug="0"&gt;改为<br />
&lt;Server port="11001" shutdown="SHUTDOWN" debug="0"&gt;<br />
<br />
&lt;Connector port="8080"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; maxThreads="150" minSpareThreads="25" maxSpareThreads="75"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enableLookups="false" redirectPort="8443" acceptCount="100"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; debug="0" connectionTimeout="20000"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; disableUploadTimeout="true" URIEncoding="UTF-8"/&gt;改为<br />
&lt;Connector port="11002"<br />
......<br />
<br />
作loadbalance的话，上面connector可以注释掉。<br />
<br />
&lt;Connector port="8009"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enableLookups="false" redirectPort="8443" debug="0"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protocol="AJP/1.3" /&gt;改为<br />
&lt;Connector port="11003"<br />
......<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
tomcat2/conf/server.xml<br />
&lt;Server port="8005" shutdown="SHUTDOWN" debug="0"&gt;改为<br />
&lt;Server port="12001" shutdown="SHUTDOWN" debug="0"&gt;<br />
<br />
&lt;Connector port="8080"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; maxThreads="150" minSpareThreads="25" maxSpareThreads="75"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enableLookups="false" redirectPort="8443" acceptCount="100"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; debug="0" connectionTimeout="20000"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; disableUploadTimeout="true" URIEncoding="UTF-8"/&gt;改为<br />
&lt;Connector port="12002"<br />
......<br />
上面这个connector同样也注释掉。<br />
<br />
&lt;Connector port="8009"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enableLookups="false" redirectPort="8443" debug="0"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protocol="AJP/1.3" /&gt;改为<br />
&lt;Connector port="12003" <br />
<br />
<br />
<br />
D 安装JK<br />
<br />
#cd /usr/local/<br />
# tar xzvf jakarta-tomcat-connectors-1.2.14-src.tar.gz<br />
#cd jakarta-tomcat-connectors-1.2.14-src/native<br />
#./buildconf.sh<br />
#./configure --with-apxs=/usr/local/apache/bin/apxs<br />
#make<br />
#make install<br />
#cd /opt/jakarta-tomcat-connectors- jk1.2.14-src/jk/native/apache-2.0/<br />
#cp mod_jk.so /opt/apache/modules/<br />
<br />
<br />
<br />
<br />
E 系统整合 <br />
<br />
#vi /opt/apache/conf/httpd.conf<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在文件最末尾加上如下语句 <br />
<br />
include conf/mod_jk.conf <br />
<br />
<br />
# Configure mod_jk.conf<br />
<br />
在conf目录下创建mod_jk.conf文件，内容如下：<br />
<br />
--------------------------mod_jk.conf--------------------------<br />
# Load mod_jk module<br />
LoadModule jk_module modules/mod_jk.so<br />
<br />
<br />
# Where to find workers.properties<br />
JkWorkersFile conf/workers.properties<br />
<br />
# Where to put jk logs<br />
JkLogFile logs/mod_jk.log<br />
<br />
# Set the jk log level [debug/error/info]<br />
JkLogLevel info<br />
<br />
# Select the log format<br />
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "<br />
<br />
# JkRequestLogFormat set the request format<br />
JkRequestLogFormat "%w %V %T"<br />
<br />
#指定那些请求交给tomcat处理,"controller"为在workers.propertise里指定的负载分配控制器<br />
JkMount /*.jsp loadbalancer（这个loadbalancer是下面worker.list最后一个值）<br />
<br />
如果还要指定*.do也进行分流就再加一行<br />
JkMount /*.do loadbalancer<br />
<br />
如果你想对所有的请求进行分流只需要写成<br />
JkMount /* loadbalancer<br />
<br />
<br />
--------------------------mod_jk.conf--------------------------<br />
<br />
编辑workers.properties<br />
#vi /opt/apache/conf/workers.properties <br />
<br />
#<br />
# workers.properties<br />
#<br />
<br />
# list the workers by name<br />
<br />
worker.list=tomcat1, tomcat2, loadbalancer<br />
<br />
# ------------------------<br />
<br />
# First tomcat server<br />
<br />
# ------------------------<br />
<br />
worker.tomcat1.port=11003<br />
worker.tomcat1.host=127.0.0.1<br />
worker.tomcat1.type=ajp13<br />
<br />
# Specify the size of the open connection cache.<br />
<br />
#worker.tomcat1.cachesize<br />
#<br />
# Specifies the load balance factor when used with<br />
<br />
# a load balancing worker.<br />
<br />
# Note:<br />
<br />
# ----&gt; lbfactor must be &gt; 0<br />
<br />
# ----&gt; Low lbfactor means less work done by the worker.<br />
<br />
worker.tomcat1.lbfactor=100<br />
<br />
# ------------------------<br />
# Second tomcat server<br />
# ------------------------<br />
<br />
worker.tomcat2.port=12003<br />
worker.tomcat2.host=127.0.0.1<br />
worker.tomcat2.type=ajp13<br />
<br />
# Specify the size of the open connection cache.<br />
#worker.tomcat2.cachesize<br />
#<br />
<br />
# Specifies the load balance factor when used with<br />
# a load balancing worker.<br />
# Note:<br />
<br />
# ----&gt; lbfactor must be &gt; 0<br />
# ----&gt; Low lbfactor means less work done by the worker.<br />
worker.tomcat2.lbfactor=100<br />
<br />
# ------------------------<br />
<br />
# Load Balancer worker<br />
<br />
# ------------------------<br />
<br />
# The loadbalancer (type lb) worker performs weighted round-robin<br />
<br />
# load balancing with sticky sessions.<br />
<br />
# Note:<br />
<br />
# ----&gt; If a worker dies, the load balancer will check its state<br />
<br />
# once in a while. Until then all work is redirected to peer<br />
<br />
# worker.<br />
worker.loadbalancer.type=lb<br />
worker.loadbalancer.balanced_workers=tomcat1, tomcat2<br />
<br />
#<br />
# END workers.properties<br />
#<br />
<br />
<br />
cluster配置，如果不配置cluster只是做loadbalance不需要<br />
修改server.xml中的engine<br />
#vi /opt/tomcat/conf/server.xml <br />
<br />
在120行左右修改原来的, 添加jvmRoute="tomcat1"<br />
<br />
&lt;Engine name="Standalone" defaultHost="localhost" jvmRoute="tomcat1"&gt;<br />
<br />
若第二台tomcat，添加jvmRoute的修改为tomcat2 <br />
<br />
<br />
至此，系统已经整个完毕&nbsp; 启动apache和tomcat服务 如果不放心可以编写一个测试<br />
<br />
在其中一个tomcat的webapps中建立一个目录TestCluster，里面新建一个test.jsp,内容为<br />
<br />
<br />
&lt;%<br />
System.out.println("===========================");<br />
%&gt;<br />
<br />
把TestCluster放到tomcat1,tomcat2的webapps下<br />
<br />
启动apache,tomcat1,tomcat2,进行测试<br />
通过 http://localhost/TestCluster/test.jsp 访问，多刷新几次页面，查看Tomcat1和Tomcat2 logs目录下面的catalina.out<br />
文件，你将可以看到打印了一行行"==========================="，并且从统计上来说，<br />
大约在tomcat2打印的数量和在Tomcat1中一样，<br />
如果lbfactor不一样的话，可以看到请求会被tomcat1,tomcat2按照不同的权重分流处理,实现了负载均衡。 <br />
<br />
<br />
自动重启<br />
&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp; 将如下内容添加至/etc/rc.d/rc.local文件末尾，以便系统启动后开启apache,tomcat服务 <br />
<br />
/usr/local/tomcat1/bin/startup.sh<br />
/usr/local/tomcat2/bin/startup.sh<br />
/opt/apache/bin/apachectl start <br />
<br />
<br />
这样做是不是够呢，比如说一个浏览器访问的时候开始被分发给A sever，然后又分发给B server，那么<br />
session里面的数据就不一致了或不正确了。两个问题，一个是apahce已经实现了，对于同一个浏览器通过来的请求会绑定到同一个server，那就没有问题。但是通过下面的测试发现不是的。<br />
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;</span><span style="background-color: rgb(255, 255, 0); color: rgb(0, 0, 0);">&lt;%</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">@&nbsp;page&nbsp;contentType</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">=</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">"</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">text/html;&nbsp;charset=GBK</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">"</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;</span><span style="background-color: rgb(255, 255, 0); color: rgb(0, 0, 0);">%&gt;</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="background-color: rgb(255, 255, 0); color: rgb(0, 0, 0);">&lt;%</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">@&nbsp;page&nbsp;import</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">=</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">"</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">java.util.*</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">"</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;</span><span style="background-color: rgb(255, 255, 0); color: rgb(0, 0, 0);">%&gt;</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">html</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">head</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">title</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">Cluster&nbsp;App&nbsp;Test</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">title</span><span style="color: rgb(0, 0, 255);">&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">head</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">body</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
Server&nbsp;Info:<br />
</span><span style="background-color: rgb(255, 255, 0); color: rgb(0, 0, 0);">&lt;%</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);"><br />
out.println(request.getLocalAddr()&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">+</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">"</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;:&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">"</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">+</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;request.getLocalPort()</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">+</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">"</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&lt;br&gt;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">"</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">);</span><span style="background-color: rgb(255, 255, 0); color: rgb(0, 0, 0);">%&gt;</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="background-color: rgb(255, 255, 0); color: rgb(0, 0, 0);">&lt;%</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;out.println(</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">"</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&lt;br&gt;&nbsp;ID&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">"</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">+</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;session.getId()</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">+</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">"</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&lt;br&gt;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">"</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">);<br />
&nbsp;&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">//</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;如果有新的&nbsp;Session&nbsp;属性设置<br />
&nbsp;&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 255);">String</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;dataName&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">=</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;request.getParameter(</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">"</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">dataName</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">"</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">);<br />
&nbsp;&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 255);">if</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;(dataName&nbsp;!</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">=</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 255);">null</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&amp;&amp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;dataName.length()&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&gt;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">0</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 255);">String</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;dataValue&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">=</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;request.getParameter(</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">"</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">dataValue</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">"</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session.setAttribute(dataName,&nbsp;dataValue);<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;out.print(</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">"</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&lt;b&gt;Session&nbsp;列表&lt;/b&gt;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">"</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">);<br />
&nbsp;&nbsp;Enumeration&nbsp;e&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">=</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;session.getAttributeNames();<br />
&nbsp;&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 255);">while</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;(e.hasMoreElements())&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 255);">String</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;name&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">=</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;(</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 255);">String</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">)e.nextElement();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 255);">String</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;value&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">=</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;session.getAttribute(name).toString();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.println(&nbsp;name&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">+</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">"</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;=&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">"</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">+</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;value</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">+</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">"</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&lt;br&gt;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">"</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&nbsp;name&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">+</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">"</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;=&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">"</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">+</span><span style="background-color: rgb(245, 245, 245); color: rgb(0, 0, 0);">&nbsp;value);<br />
&nbsp;&nbsp;&nbsp;}<br />
</span><span style="background-color: rgb(255, 255, 0); color: rgb(0, 0, 0);">%&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">form&nbsp;</span><span style="color: rgb(255, 0, 0);">action</span><span style="color: rgb(0, 0, 255);">="index.jsp"</span><span style="color: rgb(255, 0, 0);">&nbsp;method</span><span style="color: rgb(0, 0, 255);">="POST"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;名称:</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">input&nbsp;</span><span style="color: rgb(255, 0, 0);">type</span><span style="color: rgb(0, 0, 255);">=text&nbsp;</span><span style="color: rgb(255, 0, 0);">size</span><span style="color: rgb(0, 0, 255);">=20&nbsp;</span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="dataName"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">br</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;值:</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">input&nbsp;</span><span style="color: rgb(255, 0, 0);">type</span><span style="color: rgb(0, 0, 255);">=text&nbsp;</span><span style="color: rgb(255, 0, 0);">size</span><span style="color: rgb(0, 0, 255);">=20&nbsp;</span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="dataValue"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">br</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">input&nbsp;</span><span style="color: rgb(255, 0, 0);">type</span><span style="color: rgb(0, 0, 255);">=submit</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">form</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">body</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">html</span><span style="color: rgb(0, 0, 255);">&gt;</span></div>
<br />
是需要其他配置还是？另一个方法就是session的复制，及集群功能。<br />
配置集群的方法参考&#8220;链接&#8221;中的一篇文章就可以了。<br />
<br />
apache和tomcat虚拟机设置：<br />
1，在apache中 注销DocumentRoot，ServerName，Directory 等行（Directory包括的也<br />
<br />
是）。<br />
2，把conf文件中的Include conf/extra/httpd-vhosts.conf的注销去掉，这个文件专<br />
<br />
门用于配置虚拟主机。<br />
3，设置conf文件的listen 为你的ip<br />
4，假设apache的项目在usr/webapps下，项目的域名为www.mydomain.com,并在isp做好<br />
<br />
了域名解析指向当前服务器的IP<br />
5，打开conf/extra/httpd-vhosts.conf ,添加如下内容<br />
NameVirtualHost *:80<br />
<br />
&lt;VirtualHost *:80&gt;<br />
ServerAdmin admin@yazhouly.cn<br />
ServerName www.mydomain.com<br />
DocumentRoot "/usr/webapps/test"<br />
&lt;Directory /&gt;<br />
&nbsp;&nbsp;&nbsp; Options FollowSymLinks<br />
&nbsp;&nbsp;&nbsp; AllowOverride None<br />
&nbsp;&nbsp;&nbsp; Order deny,allow<br />
&nbsp;&nbsp;&nbsp; Deny from all<br />
&lt;/Directory&gt;<br />
&lt;Directory "/usr/webapps/test"&gt;<br />
&nbsp;&nbsp;&nbsp; Options Indexes FollowSymLinks<br />
&nbsp;&nbsp;&nbsp; AllowOverride None<br />
&nbsp;&nbsp;&nbsp; Order allow,deny<br />
&nbsp;&nbsp;&nbsp; Allow from all<br />
&lt;/Directory&gt;<br />
<br />
JkMount /* loadbalancer<br />
&lt;/VirtualHost&gt;<br />
其中最后四行表示关于jsp的内容都转交给tomcat处理，虽然我们在配置连接器的时候<br />
<br />
，已经配置了，但是在虚拟机设置后，还是要单独加上这几句，其中work就是<br />
<br />
mod_jk.conf中配置的代理名。<br />
打开tomcat目录conf下面的server.xml<br />
添加主机信息<br />
&nbsp;&lt;Host name="localhost"&nbsp; appBase="/usr/webapps/test"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unpackWARs="true" autoDeploy="true"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xmlValidation="false" xmlNamespaceAware="false"&gt;<br />
&lt;Context path="" docBase="/usr/webapps/test" debug="0" reloadable="true" <br />
<br />
crossContext="true"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Host&gt;<br />
保存 重新启动apache<br />
在地址栏中输入<br />
www.mydomain.com<br />
就会出现你的首页<br />
<br />
<strong><font size="4">遇到的问题</font></strong> <br />
<strong>1）启动时产生 Error receiving mcast package</strong> <br />
经测试发现，我用的ADSL,如果我联网，则会报这个异常，如果断网则不会产生。看来那个 <br />
tcpListenAddress="192.168.0.1" <br />
需要使用外网的IP地址才可以。 <br />
<strong>2）启动异常，一般是端口被占用</strong> <br />
请仔细看各个server.xml配置文件，各个端口不能相同<br />
<br />
3)如果不能做cluster只做load balance那么jvm="tomcat1"和jvm="tomcat2"这两部分内容必须保留，<br />
cluster保持注释状态，&lt;distributable/&gt;不需要。<br />
<br />
<img src ="http://www.blogjava.net/persister/aggbug/298279.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-10-14 20:28 <a href="http://www.blogjava.net/persister/archive/2009/10/14/298279.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JspSmart之upload组件源码</title><link>http://www.blogjava.net/persister/archive/2009/10/13/298084.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Tue, 13 Oct 2009 09:08:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/10/13/298084.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/298084.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/10/13/298084.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/298084.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/298084.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->&nbsp;&nbsp;&nbsp;1&nbsp;File.java&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;3&nbsp;import&n...&nbsp;&nbsp;<a href='http://www.blogjava.net/persister/archive/2009/10/13/298084.html'>阅读全文</a><img src ="http://www.blogjava.net/persister/aggbug/298084.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-10-13 17:08 <a href="http://www.blogjava.net/persister/archive/2009/10/13/298084.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>html中的Image标签及Servlet获取图片</title><link>http://www.blogjava.net/persister/archive/2009/10/02/297101.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Fri, 02 Oct 2009 06:12:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/10/02/297101.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/297101.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/10/02/297101.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/297101.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/297101.html</trackback:ping><description><![CDATA[Image属性src是可以设置servlet的路径的，即从servlet获取图片<br />
如在web.xml配置：<br />
<br />
&nbsp; &lt;servlet&gt;<br />
&nbsp;&nbsp; &nbsp;&lt;servlet-name&gt;GenerateImageServlet&lt;/servlet-name&gt;<br />
&nbsp;&nbsp; &nbsp;&lt;servlet-class&gt;org.bruce.util.GenerateImageServlet&lt;/servlet-class&gt;<br />
&nbsp; &lt;/servlet&gt;<br />
&nbsp; &lt;servlet-mapping&gt;<br />
&nbsp;&nbsp; &nbsp;&lt;servlet-name&gt;GenerateImageServlet&lt;/servlet-name&gt;<br />
&nbsp;&nbsp; &nbsp;&lt;url-pattern&gt;/getImage&lt;/url-pattern&gt;<br />
&nbsp; &lt;/servlet-mapping&gt;<br />
<br />
然后在jsp文件中：<br />
<br />
&lt;img src="getImage" title="美女"&gt;<br />
<br />
这样就可以得到图片了。这里就给动态获取图片提供了一种途径。<br />
比如可以通过src="getImage?id=1000"就可以得到1000号图片。<br />
<br />
还可以采用JavaScript onclick方法刷新图片，网上参考资料采用如下方法：<br />
<br />
&lt;img src="valid" onclick="regenerate(this)" title="美女"&gt;<br />
&lt;script&gt;<br />
function regenerate(this){<br />
&nbsp;&nbsp; &nbsp;this.src="getImage";<br />
}<br />
&lt;/script&gt;<br />
<br />
尝试后，发现这种方法无效，由于路径没变，浏览器不会重新发起请求。这里我采用另外一种技巧：<br />
<br />
&nbsp;&nbsp; &nbsp;&lt;script type="text/javascript"&gt;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;function regenerate(obj){var date=new Dat();<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; obj.src="getImage?time=" + date.getSeconds();<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp; &nbsp;&lt;/script&gt;<br />
<br />
这样由于路径发生了变化，就重新发起请求，轻松实现点击更新图片内容。<br />
在生成验证码的时候这个方法很管用，因为当页面显示的验证码看不清时，应该提供方法重新获取一张。<br />
<br />
<img src ="http://www.blogjava.net/persister/aggbug/297101.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-10-02 14:12 <a href="http://www.blogjava.net/persister/archive/2009/10/02/297101.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate二级缓存</title><link>http://www.blogjava.net/persister/archive/2009/09/30/297047.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Wed, 30 Sep 2009 11:02:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/09/30/297047.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/297047.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/09/30/297047.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/297047.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/297047.html</trackback:ping><description><![CDATA[Hibernate二级缓存<br />
<br />
在一个数据库系统中，如果缓存设置的合适，那么可以极大的提高系统的效率，Hibernate作为一个ORM工具<br />
提供了缓存的机制，包括一级（Session级）缓存和二级（SessionFactory级）缓存。这里主要总结一下二级缓存。<br />
<br />
1.首先需要在hibernate.cfg.xml中配置，当然需要导入缓存的jar包<br />
<br />
<div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; width: 98%;"><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property&nbsp;</span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="hibernate.cache.use_query_cache"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">true</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property&nbsp;</span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="hibernate.cache.provider_class"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">org.hibernate.cache.EhCacheProvider</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span></div>
<br />
<br />
&nbsp;&nbsp; &nbsp;hibernate.cache.use_query_cache必须配置，如果想缓存使用findall()、list()、Iterator()、createCriteria()、<br />
&nbsp;&nbsp; &nbsp;createQuery()等方法获得的数据结果集。<br />
<br />
2.在每个实体的hbm文件中配置cache元素，usage可以是read-only或者是read-write等。<br />
&nbsp;&nbsp; <br />
<div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; width: 98%;"><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">hibernate-mapping</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">class&nbsp;</span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="com.xxx.db.base.City"</span><span style="color: rgb(255, 0, 0);">&nbsp;table</span><span style="color: rgb(0, 0, 255);">="city"</span><span style="color: rgb(255, 0, 0);">&nbsp;catalog</span><span style="color: rgb(0, 0, 255);">="haosou"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">cache&nbsp;</span><span style="color: rgb(255, 0, 0);">usage</span><span style="color: rgb(0, 0, 255);">="nonstrict-read-write"</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">id&nbsp;</span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="citycode"</span><span style="color: rgb(255, 0, 0);">&nbsp;type</span><span style="color: rgb(0, 0, 255);">="string"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">column&nbsp;</span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="citycode"</span><span style="color: rgb(255, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">generator&nbsp;</span><span style="color: rgb(255, 0, 0);">class</span><span style="color: rgb(0, 0, 255);">="assigned"</span><span style="color: rgb(255, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property&nbsp;</span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="city"</span><span style="color: rgb(255, 0, 0);">&nbsp;type</span><span style="color: rgb(0, 0, 255);">="string"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">column&nbsp;</span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="city"</span><span style="color: rgb(255, 0, 0);">&nbsp;not-null</span><span style="color: rgb(0, 0, 255);">="true"</span><span style="color: rgb(255, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">set&nbsp;</span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="districts"</span><span style="color: rgb(255, 0, 0);">&nbsp;table</span><span style="color: rgb(0, 0, 255);">="district"</span><span style="color: rgb(255, 0, 0);">&nbsp;cascade</span><span style="color: rgb(0, 0, 255);">="all"</span><span style="color: rgb(255, 0, 0);">&nbsp;inverse</span><span style="color: rgb(0, 0, 255);">="true"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">key&nbsp;</span><span style="color: rgb(255, 0, 0);">column</span><span style="color: rgb(0, 0, 255);">="citycode"</span><span style="color: rgb(255, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">one-to-many&nbsp;</span><span style="color: rgb(255, 0, 0);">class</span><span style="color: rgb(0, 0, 255);">="com.haosou.db.base.District"</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">set</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">class</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">hibernate-mapping</span><span style="color: rgb(0, 0, 255);">&gt;</span></div>
<br />
如果相对具体某个类的缓存进行特定的配置，需要在ehcache.xml进行配置：<br />
<br />
<div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; width: 98%;"><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">cache&nbsp;</span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="org.qiujy.domain.cachedemo.Category"</span><span style="color: rgb(255, 0, 0);">&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxElementsInMemory</span><span style="color: rgb(0, 0, 255);">="100"</span><span style="color: rgb(255, 0, 0);">&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;eternal</span><span style="color: rgb(0, 0, 255);">="true"</span><span style="color: rgb(255, 0, 0);">&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timeToIdleSeconds</span><span style="color: rgb(0, 0, 255);">="0"</span><span style="color: rgb(255, 0, 0);">&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timeToLiveSeconds</span><span style="color: rgb(0, 0, 255);">="0"</span><span style="color: rgb(255, 0, 0);">&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;overflowToDisk</span><span style="color: rgb(0, 0, 255);">="false"</span><span style="color: rgb(255, 0, 0);">&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
</span></div>
<br />
3.Query或Criteria()时设置其setCacheable(true);<br />
<br />
<div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; width: 98%;"><span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;Session&nbsp;session&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;HibernateSessionFactory.getCurrentSession();<br />
&nbsp;&nbsp;&nbsp;&nbsp;Query&nbsp;q&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;session.createQuery(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">from&nbsp;City</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;q.setCacheable(</span><span style="color: rgb(0, 0, 255);">true</span><span style="color: rgb(0, 0, 0);">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);">&nbsp;q.list();<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Session&nbsp;session&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;HibernateSessionFactory.getCurrentSession();<br />
&nbsp;&nbsp;&nbsp;&nbsp;Query&nbsp;q&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;session.createQuery(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">from&nbsp;District&nbsp;d&nbsp;where&nbsp;d.city.citycode='</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);">&nbsp;cityId&nbsp;</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;q.setCacheable(</span><span style="color: rgb(0, 0, 255);">true</span><span style="color: rgb(0, 0, 0);">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);">&nbsp;q.list();</span></div>
<br />
<br />
&nbsp;&nbsp; &nbsp;执行以上代码时，第一次会查询数据库，但是后面就直接从缓存中查询，而不会使用数据库的连接，提高了性能。<br />
&nbsp;&nbsp; &nbsp;以上任一环节都不能少，比如cache元素没有配置，那么就会导致查询district的时候发起N个数据库的连接，这样会极大的降低性能。
<img src ="http://www.blogjava.net/persister/aggbug/297047.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-09-30 19:02 <a href="http://www.blogjava.net/persister/archive/2009/09/30/297047.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>OFBiz的中文乱码解决方案</title><link>http://www.blogjava.net/persister/archive/2009/08/10/290568.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Mon, 10 Aug 2009 08:58:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/08/10/290568.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/290568.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/08/10/290568.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/290568.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/290568.html</trackback:ping><description><![CDATA[<p>OFBiz开发时遇到乱码的问题，MySQL数据库插入中文数据时出现了一个问题，报告中文错误：incorrect string value ．．．．．</p>
<p>1.这时由于字符编码不一致导致的，应该将数据库对应的表或coloum改成uft-8，所以如果在CustomerExtra这表中存储中文的话，需要将<br />
&nbsp; 此表另外还有operationlog表的charset改成utf-8</p>
<p>2.Servlet中字符显示为证券的中文，而且表也设置为utf-8，但是数据库和页面还是乱码，怎么回事？<br />
&nbsp; 这里需要修改jdbc url的参数，如将jdbc:mysql://localhost/ccbportal?zeroDateTimeBehavior=convertToNull<br />
&nbsp; 改成：jdbc:mysql://localhost/ccbportal?zeroDateTimeBehavior=convertToNull&amp;amp;useUnicode=true&amp;amp;characterEncoding=UTF-8</p>
<p>3.前台输入的是中文，到后台就变成了乱码，怎么回事？<br />
&nbsp; 无论何种表单提交都可以在后台的java文件中通过String des = new String(s.getBytes("iso8859-1"),"UTF-8");<br />
&nbsp; 来转换成你想要的UTF－8编码方式。但如果每处都加词句太麻烦，故分post和get两种方式区分提交。<br />
&nbsp; 写一个Filter即可解决问题：<br />
&nbsp;
</p>
<div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 128, 128);">&nbsp;1</span>&nbsp;<span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 128, 128);">&nbsp;2</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;import&nbsp;java.io.IOException;<br />
</span><span style="color: rgb(0, 128, 128);">&nbsp;3</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;import&nbsp;javax.servlet.ServletException;<br />
</span><span style="color: rgb(0, 128, 128);">&nbsp;4</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;import&nbsp;javax.servlet.Filter;<br />
</span><span style="color: rgb(0, 128, 128);">&nbsp;5</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;import&nbsp;javax.servlet.FilterChain;<br />
</span><span style="color: rgb(0, 128, 128);">&nbsp;6</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;import&nbsp;javax.servlet.FilterConfig;<br />
</span><span style="color: rgb(0, 128, 128);">&nbsp;7</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;<br />
</span><span style="color: rgb(0, 128, 128);">&nbsp;8</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;import&nbsp;javax.servlet.ServletRequest;<br />
</span><span style="color: rgb(0, 128, 128);">&nbsp;9</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;import&nbsp;javax.servlet.ServletResponse;<br />
</span><span style="color: rgb(0, 128, 128);">10</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;<br />
</span><span style="color: rgb(0, 128, 128);">11</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;public&nbsp;class&nbsp;SetCharacterEncodingFilter&nbsp;implements&nbsp;Filter&nbsp;{<br />
</span><span style="color: rgb(0, 128, 128);">12</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;<br />
</span><span style="color: rgb(0, 128, 128);">13</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;protected&nbsp;String&nbsp;encoding&nbsp;=&nbsp;"GBK";<br />
</span><span style="color: rgb(0, 128, 128);">14</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;<br />
</span><span style="color: rgb(0, 128, 128);">15</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;protected&nbsp;FilterConfig&nbsp;filterConfig&nbsp;=&nbsp;null;<br />
</span><span style="color: rgb(0, 128, 128);">16</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;<br />
</span><span style="color: rgb(0, 128, 128);">17</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;protected&nbsp;boolean&nbsp;ignore&nbsp;=&nbsp;true;<br />
</span><span style="color: rgb(0, 128, 128);">18</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;<br />
</span><span style="color: rgb(0, 128, 128);">19</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;public&nbsp;void&nbsp;init(FilterConfig&nbsp;filterConfig)&nbsp;throws&nbsp;ServletException&nbsp;{<br />
</span><span style="color: rgb(0, 128, 128);">20</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;this.filterConfig&nbsp;=&nbsp;filterConfig;<br />
</span><span style="color: rgb(0, 128, 128);">21</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;this.encoding&nbsp;=&nbsp;filterConfig.getInitParameter("encoding");<br />
</span><span style="color: rgb(0, 128, 128);">22</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;String&nbsp;value&nbsp;=&nbsp;filterConfig.getInitParameter("ignore");<br />
</span><span style="color: rgb(0, 128, 128);">23</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;if&nbsp;(value&nbsp;==&nbsp;null)<br />
</span><span style="color: rgb(0, 128, 128);">24</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;this.ignore&nbsp;=&nbsp;true;<br />
</span><span style="color: rgb(0, 128, 128);">25</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;else&nbsp;if&nbsp;(value.equalsIgnoreCase("true"))<br />
</span><span style="color: rgb(0, 128, 128);">26</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;this.ignore&nbsp;=&nbsp;true;<br />
</span><span style="color: rgb(0, 128, 128);">27</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;else&nbsp;if&nbsp;(value.equalsIgnoreCase("yes"))<br />
</span><span style="color: rgb(0, 128, 128);">28</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;this.ignore&nbsp;=&nbsp;true;<br />
</span><span style="color: rgb(0, 128, 128);">29</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;else<br />
</span><span style="color: rgb(0, 128, 128);">30</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;this.ignore&nbsp;=&nbsp;false;<br />
</span><span style="color: rgb(0, 128, 128);">31</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;}<br />
</span><span style="color: rgb(0, 128, 128);">32</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;<br />
</span><span style="color: rgb(0, 128, 128);">33</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;public&nbsp;void&nbsp;doFilter(ServletRequest&nbsp;request,&nbsp;ServletResponse&nbsp;response,<br />
</span><span style="color: rgb(0, 128, 128);">34</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;FilterChain&nbsp;chain)&nbsp;throws&nbsp;IOException,&nbsp;ServletException&nbsp;{<br />
</span><span style="color: rgb(0, 128, 128);">35</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;//&nbsp;Conditionally&nbsp;select&nbsp;and&nbsp;set&nbsp;the&nbsp;character&nbsp;encoding&nbsp;to&nbsp;be&nbsp;used<br />
</span><span style="color: rgb(0, 128, 128);">36</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;if&nbsp;(ignore&nbsp;||&nbsp;(request.getCharacterEncoding()&nbsp;==&nbsp;null))&nbsp;{<br />
</span><span style="color: rgb(0, 128, 128);">37</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;encoding&nbsp;=&nbsp;selectEncoding(request);<br />
</span><span style="color: rgb(0, 128, 128);">38</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(encoding&nbsp;!=&nbsp;null)&nbsp;{<br />
</span><span style="color: rgb(0, 128, 128);">39</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;request.setCharacterEncoding(encoding);<br />
</span><span style="color: rgb(0, 128, 128);">40</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</span><span style="color: rgb(0, 128, 128);">41</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;<br />
</span><span style="color: rgb(0, 128, 128);">42</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;}<br />
</span><span style="color: rgb(0, 128, 128);">43</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;//&nbsp;Pass&nbsp;control&nbsp;on&nbsp;to&nbsp;the&nbsp;next&nbsp;filter<br />
</span><span style="color: rgb(0, 128, 128);">44</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;chain.doFilter(request,&nbsp;response);<br />
</span><span style="color: rgb(0, 128, 128);">45</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;}<br />
</span><span style="color: rgb(0, 128, 128);">46</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;<br />
</span><span style="color: rgb(0, 128, 128);">47</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;protected&nbsp;String&nbsp;selectEncoding(ServletRequest&nbsp;request)&nbsp;{<br />
</span><span style="color: rgb(0, 128, 128);">48</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;return&nbsp;(this.encoding);<br />
</span><span style="color: rgb(0, 128, 128);">49</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;}<br />
</span><span style="color: rgb(0, 128, 128);">50</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;<br />
</span><span style="color: rgb(0, 128, 128);">51</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;public&nbsp;void&nbsp;destroy()&nbsp;{<br />
</span><span style="color: rgb(0, 128, 128);">52</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;this.encoding&nbsp;=&nbsp;null;<br />
</span><span style="color: rgb(0, 128, 128);">53</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;this.filterConfig&nbsp;=&nbsp;null;<br />
</span><span style="color: rgb(0, 128, 128);">54</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;}<br />
</span><span style="color: rgb(0, 128, 128);">55</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;}<br />
</span><span style="color: rgb(0, 128, 128);">56</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp; <br />
</span></div>
<p><br />
web.xml添加此Filter：<br />
</p>
<div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 128, 128);">&nbsp;1</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">filter</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 128, 128);">&nbsp;2</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">filter-name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">encodeFilter</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">filter-name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 128, 128);">&nbsp;3</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">filter-class</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">&nbsp;com.aicent.ccb.filter.SetCharacterEncodingFilter</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">filter-class</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 128, 128);">&nbsp;4</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">init-param</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 128, 128);">&nbsp;5</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">param-name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">encoding</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">param-name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 128, 128);">&nbsp;6</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">param-value</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">GBK</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">param-value</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 128, 128);">&nbsp;7</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">init-param</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 128, 128);">&nbsp;8</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">init-param</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 128, 128);">&nbsp;9</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">param-name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">ignore</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">param-name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 128, 128);">10</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">param-value</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">true</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">param-value</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 128, 128);">11</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">init-param</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 128, 128);">12</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">filter</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 128, 128);">13</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">filter-mapping</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 128, 128);">14</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">filter-name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">encodeFilter</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">filter-name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 128, 128);">15</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">url-pattern</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">/control/*</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">url-pattern</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 128, 128);">16</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">filter-mapping</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">&nbsp; <br />
</span></div>
<p>&nbsp;</p>
<img src ="http://www.blogjava.net/persister/aggbug/290568.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-08-10 16:58 <a href="http://www.blogjava.net/persister/archive/2009/08/10/290568.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java里面中文排序问题</title><link>http://www.blogjava.net/persister/archive/2009/07/12/286477.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Sun, 12 Jul 2009 13:07:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/07/12/286477.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/286477.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/07/12/286477.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/286477.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/286477.html</trackback:ping><description><![CDATA[<p>package com.liuby.test;</p>
<p>import java.text.Collator;<br />
import java.util.Arrays;<br />
import java.util.Locale;</p>
<p>public class SortingChinese {<br />
&nbsp;public static void main(String[] args) {<br />
&nbsp;&nbsp;String[] names = { "张山", "李四", "王五", "爱情", "幸福", "English", "EngTi", "EngMi", "王六", "郑森", "郑"};<br />
&nbsp;&nbsp;Arrays.sort(names, Collator.getInstance(Locale.CHINA));<br />
&nbsp;&nbsp;for (int i = 0; i &lt; names.length; i++)<br />
&nbsp;&nbsp;&nbsp;System.out.println(names[i]);<br />
//&nbsp;&nbsp;English<br />
//&nbsp;&nbsp;EngMi<br />
//&nbsp;&nbsp;EngTi<br />
//&nbsp;&nbsp;爱情<br />
//&nbsp;&nbsp;李四<br />
//&nbsp;&nbsp;王六<br />
//&nbsp;&nbsp;王五<br />
//&nbsp;&nbsp;幸福<br />
//&nbsp;&nbsp;张山<br />
//&nbsp;&nbsp;郑<br />
//&nbsp;&nbsp;郑森<br />
&nbsp;}<br />
}<br />
</p>
<img src ="http://www.blogjava.net/persister/aggbug/286477.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-07-12 21:07 <a href="http://www.blogjava.net/persister/archive/2009/07/12/286477.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDBM学习八（Record）</title><link>http://www.blogjava.net/persister/archive/2009/05/19/271484.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Tue, 19 May 2009 02:47:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/05/19/271484.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/271484.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/05/19/271484.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/271484.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/271484.html</trackback:ping><description><![CDATA[<p><strong style="font-size: 12pt">1.record概念<br />
</strong><br />
Record是从使用者角度来说的，如使用PhysicalRowIdManager插入一个10000byte的Record<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp; byte[] data = TestUtil.makeRecord(10000, (byte) 1);</p>
<p>&nbsp;&nbsp;&nbsp; Location loc = physMgr.insert( data, 0, data.length );</p>
<p>每一个记录都会被DataPage和RecordHeader进行封装：</p>
<p>&nbsp;&nbsp;&nbsp; curBlock = file.get( start );<br />
&nbsp;&nbsp;&nbsp; curPage = DataPage.getDataPageView( curBlock );<br />
&nbsp;&nbsp;&nbsp; curPage.setFirst( DataPage.O_DATA );<br />
&nbsp;&nbsp;&nbsp; RecordHeader hdr = new RecordHeader( curBlock, DataPage.O_DATA );<br />
&nbsp;&nbsp;&nbsp; hdr.setAvailableSize( 0 );<br />
&nbsp;&nbsp;&nbsp; hdr.setCurrentSize( 0 );<br />
&nbsp;&nbsp;&nbsp; <br />
一个BlockIo最多只能存储8164（RecordFile.BLOCK_SIZE - DataPage.O_DATA - RecordHeader.SIZE）个bytes<br />
如果不需要RecordHeader（这个BlockIo全都是data，不需要RecordHeader），那么可以存储8172（RecordFile.BLOCK_SIZE - DataPage.O_DATA）个bytes。两者相差RecordHeader.SIZE（8）个bytes。</p>
<p>&nbsp;&nbsp;&nbsp; curBlock = file.get( start );<br />
&nbsp;&nbsp;&nbsp; curPage = DataPage.getDataPageView( curBlock );<br />
&nbsp;&nbsp;&nbsp; curPage.setFirst( (short) 0 ); // no rowids, just data</p>
<p>上面最后一行代码curPage.setFirst( (short) 0 )并不是说从0的位置开始可以存储数据，而是从DataPage.O_DATA（20）开始存储数据：<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( leftToWrite &gt; 0 ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; block = file.get( curs.next() );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dataOffset = DataPage.O_DATA;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p><strong style="font-size: 14pt; font-family: 宋体">2.JDBM效率<br />
</strong><br />
顺序插入记录的时候，BlockIo能够非常紧凑的使用，不会出现多余的空间遗漏，比如上面插入10000个bytes，那么第二次插入10000时，那么从第一次结束的地方开始（第二个BlockIo的offset为10000-8164+20=1856）安排第一个记录。但是如果一旦出现update的情况则不一样了，比如10000个bytes的记录被update成20000个bytes，JDBM会释放这个10000bytes的空间，在FREEPHYSIDS_PAGE中就多一个10000bytes的slot待使用。这个时候如果插入一个20bytes的记录，那么就独占这个10000bytes的空间，这就造成空间浪费。这种策略只适合查询较多的情况，不适合频繁的更新，当然可以优化，只从这个slot中取20+28个bytes空间，其他的依然放在这个slot中待使用。如果有时间，我想试试。&nbsp;</p>
<img src ="http://www.blogjava.net/persister/aggbug/271484.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-05-19 10:47 <a href="http://www.blogjava.net/persister/archive/2009/05/19/271484.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDBM学习七（部分总结）</title><link>http://www.blogjava.net/persister/archive/2009/05/18/271342.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Mon, 18 May 2009 07:35:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/05/18/271342.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/271342.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/05/18/271342.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/271342.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/271342.html</trackback:ping><description><![CDATA[<p><span style="font-family: 宋体"><strong style="font-size: 14pt">1.RecordFile</strong></span><br />
从RecordFile的commit方法部分代码：<br />
&nbsp;if (transactionsDisabled) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; long offset = node.getBlockId() * BLOCK_SIZE;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; file.seek(offset);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; file.write(node.getData());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node.setClean();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; free.add(node);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
可以断定，File被均匀（大小都为BLOCK_SIZE=8192）的分成N个BlockIo。每一个<br />
BlockIo都有一个BlockId,BlockId是从0开始顺序递增的，这样只要知道这个BlockId<br />
也就可以知道BlockIo的在RecordFile的位置了。<br />
-----------------------------------------------------------------<br />
|0&nbsp;&nbsp;&nbsp;BlockIo&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |8192<br />
-----------------------------------------------------------------<br />
|1&nbsp;&nbsp;&nbsp;BlockIo&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |8192<br />
-----------------------------------------------------------------<br />
|2&nbsp;&nbsp;&nbsp;BlockIo&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |8192<br />
-----------------------------------------------------------------<br />
.<br />
.<br />
.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
-----------------------------------------------------------------<br />
|n&nbsp;&nbsp;&nbsp;BlockIo&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |8192<br />
-----------------------------------------------------------------</p>
<p>从getNewNode方法可以知道，BlockIo不是从RecordFile里面生成出来的，而是<br />
直接new一个出来。因为RecordFile持有的是RandomAccessFile，即如果你要往里面<br />
写数据你就直接写好了。先New一个BlockIo，往BlockIo里面填值以后，你要close或者<br />
commit，那么就把BlockIo里面的数据写到这个RandomAccessFile里面就是了。<br />
&nbsp;&nbsp;&nbsp; private BlockIo getNewNode(long blockid)<br />
&nbsp;&nbsp;&nbsp; throws IOException <br />
&nbsp;&nbsp;&nbsp; {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BlockIo retval = null;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!free.isEmpty()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retval = (BlockIo) free.removeFirst();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (retval == null)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retval = new BlockIo(0, new byte[BLOCK_SIZE]);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retval.setBlockId(blockid);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retval.setView(null);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return retval;<br />
&nbsp;&nbsp;&nbsp; }</p>
<p><strong style="font-size: 14pt">2.PageHeader</strong><br />
Pageheader对每一个（应该是除了第0个，第0个被FileHeader封装）BlockIo封装，PageHeader还维护<br />
着前一个和后一个BlockIo，即通过PageHeader可以将所有的BlockIo串起来。被PageHeader封装的BlockIo<br />
也就被称为一个Page</p>
<p><strong style="font-size: 14pt">3.PageManager</strong><br />
PageManager实现了对Page的管理，包括对Page的allocate和free，获取第一个和最后一个Page，一个特定Page的前后Page，<br />
以及RecordFile的commit和rollback。</p>
<p><strong style="font-size: 14pt">4.PhysicalRow</strong><br />
PhysicalRowId，FreePhysicalRowId，FreePhysicalRowIdPage和FreePhysicalRowIdPageManager对BLockIo进行更细粒度的管理。每一个BlockIo被分成一个个PhysicalRowId（Id这个取名有歧义，其实就是BlockIo的一部分），<br />
当然一个FreePhysicalRowId也可能跨越几个BlockIo。PhysicalRowId包含一个<br />
Block Number和一个Offset，FreePhysicalRowId还有一个size来表示这块PhysicalRowId的size是多少。</p>
<p>FreePhysicalRowIdPage继承PageHeader，持有ELEMS_PER_PAGE(583)个FreePhysicalRowId供分配或者释放管理：</p>
<p>&nbsp;&nbsp;&nbsp; // slots we returned.<br />
&nbsp;&nbsp;&nbsp; FreePhysicalRowId[] slots = new FreePhysicalRowId[ELEMS_PER_PAGE];</p>
<p>为了记录分配的个数，有一个setCount方法。和PageHeader将BlockIo封装起来并且维护前后的BlockIo不同，<br />
FreePhysicalRowIdPage维护free的PhysicalRowId，这些Id是以一个数组组织起来的。相同的是都对BlockIo<br />
进行封装：<br />
&nbsp;BlockIo curBlock = _file.get(freePage);<br />
&nbsp;FreePhysicalRowIdPage fp = FreePhysicalRowIdPage<br />
&nbsp;&nbsp;&nbsp;.getFreePhysicalRowIdPageView(curBlock);<br />
&nbsp;int slot = fp.getFirstFree();<br />
&nbsp;if (slot != -1) {<br />
&nbsp;&nbsp;free = fp.alloc(slot); //这里调用了FreePhysicalRowIdPage的setCount操作，<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //这个count会写到BlockIo里面进行记录<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;break;<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;_file.release(curBlock);</p>
<p>从这里可以看到：BlockIo除了被PageHeader封装外，还会被FreePhysicalRowIdPage封装，只是FreePhysicalRowIdPage<br />
可能不会封装每一个BlockIo，只是free的这块而已。</p>
<p>这些FreePhysicalRowId拥有同样的BlockIo，offset具有一定规律：<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; /** Returns the value of the indicated slot */<br />
&nbsp;&nbsp;&nbsp; FreePhysicalRowId get(int slot) {<br />
&nbsp;if (slots[slot] == null) <br />
&nbsp;slots[slot] = new FreePhysicalRowId(block, slotToOffset(slot)); //这时的offset只是区分，没有实际意思<br />
&nbsp;return slots[slot];<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; /** Converts slot to offset */<br />
&nbsp;&nbsp;&nbsp; short slotToOffset(int slot) {<br />
&nbsp;return (short) (O_FREE +<br />
&nbsp;(slot * FreePhysicalRowId.SIZE)); //即相差FreePhysicalRowId.SIZE，14个byte<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>FreePhysicalRowId的使用大致是这样的：</p>
<p>&nbsp;byte[] data = TestUtil.makeRecord(10000, (byte) 1);</p>
<p>&nbsp;Location loc = physMgr.insert( data, 0, data.length );<br />
&nbsp;<br />
&nbsp;data = TestUtil.makeRecord(20000, (byte) 2);</p>
<p>&nbsp;Location loc2 = physMgr.update(loc, data, 0, data.length );<br />
&nbsp;<br />
&nbsp;当更新的时候，数据量变大了，那么前面的10000byte容量放不下20000个，那么就释放掉10000这块容量：<br />
&nbsp;<br />
&nbsp;free( loc )具体代码如下：<br />
&nbsp;<br />
&nbsp;free( Location id )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws IOException<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // get the rowid, and write a zero current size into it.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BlockIo curBlock = file.get( id.getBlock() );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DataPage curPage = DataPage.getDataPageView( curBlock );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RecordHeader hdr = new RecordHeader( curBlock, id.getOffset() );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hdr.setCurrentSize( 0 );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; file.release( id.getBlock(), true );</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // write the rowid to the free list<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; freeman.put( id, hdr.getAvailableSize() );<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;最后调用的是FreePhysicalRowIdPageManager的put方法：<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**<br />
&nbsp; * Puts the indicated rowid on the free list<br />
&nbsp; */<br />
&nbsp;void put(Location rowid, int size) throws IOException {</p>
<p>&nbsp;&nbsp;FreePhysicalRowId free = null;<br />
&nbsp;&nbsp;PageCursor curs = new PageCursor(_pageman, Magic.FREEPHYSIDS_PAGE);<br />
&nbsp;&nbsp;long freePage = 0;<br />
&nbsp;&nbsp;while (curs.next() != 0) {<br />
&nbsp;&nbsp;&nbsp;freePage = curs.getCurrent();<br />
&nbsp;&nbsp;&nbsp;BlockIo curBlock = _file.get(freePage);<br />
&nbsp;&nbsp;&nbsp;FreePhysicalRowIdPage fp = FreePhysicalRowIdPage<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.getFreePhysicalRowIdPageView(curBlock);<br />
&nbsp;&nbsp;&nbsp;int slot = fp.getFirstFree();<br />
&nbsp;&nbsp;&nbsp;if (slot != -1) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;free = fp.alloc(slot);<br />
&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;_file.release(curBlock);<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;if (free == null) {<br />
&nbsp;&nbsp;&nbsp;// No more space on the free list, add a page.<br />
&nbsp;&nbsp;&nbsp;freePage = _pageman.allocate(Magic.FREEPHYSIDS_PAGE);<br />
&nbsp;&nbsp;&nbsp;BlockIo curBlock = _file.get(freePage);<br />
&nbsp;&nbsp;&nbsp;FreePhysicalRowIdPage fp = FreePhysicalRowIdPage<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.getFreePhysicalRowIdPageView(curBlock);<br />
&nbsp;&nbsp;&nbsp;free = fp.alloc(0);<br />
&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;free.setBlock(rowid.getBlock());<br />
&nbsp;&nbsp;free.setOffset(rowid.getOffset());<br />
&nbsp;&nbsp;free.setSize(size);<br />
&nbsp;&nbsp;_file.release(freePage, true);<br />
&nbsp;}<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 最后几行代码就是对FreePhysicalRowId对象进行了设置，以供后面使用，见PhysicalRowIdManager的alloc方法：<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; alloc( int size )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws IOException<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Location retval = freeman.get( size );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( retval == null ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retval = allocNew( size, pageman.getLast( Magic.USED_PAGE ) );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return retval;<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; FreePhysicalRowIdPageManager的get( size )方法有如下代码：<br />
&nbsp;&nbsp;&nbsp; int slot = fp.getFirstLargerThan(size)<br />
&nbsp;&nbsp;&nbsp; retval = new Location(fp.get(slot));&nbsp; //fp.get(slot)返回一个FreePhysicalRowId，Location根据FreePhysicalRowId进行设置<br />
&nbsp;&nbsp;&nbsp; return retval;<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; FreePhysicalRowIdPage的getFirstLargerThan(size):<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**<br />
&nbsp; * Returns first slot with available size &gt;= indicated size, or -1 if no<br />
&nbsp; * slots are available.<br />
&nbsp; **/<br />
&nbsp;int getFirstLargerThan(int size) {<br />
&nbsp;&nbsp;for (int i = 0; i &lt; ELEMS_PER_PAGE; i++) {<br />
&nbsp;&nbsp;&nbsp;if (isAllocated(i) &amp;&amp; get(i).getSize() &gt;= size)&nbsp; //getSize会取到前面的setSize的值<br />
&nbsp;&nbsp;&nbsp;&nbsp;return i;<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;return -1;<br />
&nbsp;}&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; Location的构造方法如下：<br />
&nbsp;&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Creates a location based on the data of the physical rowid.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; Location(PhysicalRowId src) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; block = src.getBlock();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; offset = src.getOffset();<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; <br />
FreePhysicalRowIdPageManager只有两个方法，是对FreePhysicalRowIdPage进行管理的。类似于<br />
&nbsp;/**<br />
&nbsp; * Returns a free physical rowid of the indicated size, or null if nothing<br />
&nbsp; * was found.<br />
&nbsp; */<br />
&nbsp;Location get(int size)<br />
&nbsp;<br />
&nbsp;/**<br />
&nbsp; * Puts the indicated rowid on the free list<br />
&nbsp; */<br />
&nbsp;void put(Location rowid, int size)</p>
<p><br />
&nbsp;</p>
<img src ="http://www.blogjava.net/persister/aggbug/271342.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-05-18 15:35 <a href="http://www.blogjava.net/persister/archive/2009/05/18/271342.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDBM学习六（Physical Row）</title><link>http://www.blogjava.net/persister/archive/2009/05/13/270392.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Wed, 13 May 2009 05:26:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/05/13/270392.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/270392.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/05/13/270392.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/270392.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/270392.html</trackback:ping><description><![CDATA[<p>PhysicalRowId:A physical rowid is nothing else than a pointer to a physical location<br />
&nbsp;in a file - a (block, offset) tuple.<br />
&nbsp;里面有方法：<br />
&nbsp;/** Returns the block number */<br />
&nbsp;&nbsp;&nbsp; long getBlock() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return block.readLong(pos + O_BLOCK);<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; /** Sets the block number */<br />
&nbsp;&nbsp;&nbsp; void setBlock(long value) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; block.writeLong(pos + O_BLOCK, value);<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; 还不是很明白这个block number和rowid是什么关系，好像这个number的设置是很自由的，奇怪<br />
FreePhysicalRowId:This class extends the physical rowid with a size value to indicated<br />
&nbsp;the size of a free rowid on the free rowid list.<br />
&nbsp;这个类就是比PhysicalRowId多了一个size的设置，这个size是a free rowid的，不是很明白这句话,rowid需要这个size干吗？</p>
<p>&nbsp;FreePhysicalRowId id = ......<br />
&nbsp;id.setBlock(1);<br />
&nbsp;id.setOffset((short) 2);<br />
&nbsp;id.setSize(3);</p>
<p>FreePhysicalRowIdPage:describe a page that holds physical rowids that were freed.<br />
&nbsp;这个类管理rowid，其主要方法如下：<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; // slots we returned.<br />
&nbsp;&nbsp;&nbsp; FreePhysicalRowId[] slots = new FreePhysicalRowId[ELEMS_PER_PAGE];<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; /** Returns the number of free rowids */<br />
&nbsp;&nbsp;&nbsp; short getCount() {<br />
&nbsp; return block.readShort(O_COUNT);<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; /** Sets the number of free rowids */<br />
&nbsp;&nbsp;&nbsp; private void setCount(short i) {<br />
&nbsp; block.writeShort(O_COUNT, i);<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; /** Frees a slot */<br />
&nbsp;&nbsp;&nbsp; void free(int slot) {<br />
&nbsp; get(slot).setSize(0);<br />
&nbsp; setCount((short) (getCount() - 1));<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; /** Allocates a slot */<br />
&nbsp;&nbsp;&nbsp; FreePhysicalRowId alloc(int slot) {<br />
&nbsp; setCount((short) (getCount() + 1));<br />
&nbsp; return get(slot);<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; /** Returns true if a slot is allocated */<br />
&nbsp;&nbsp;&nbsp; boolean isAllocated(int slot) {<br />
&nbsp; return get(slot).getSize() != 0;<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; /** Returns true if a slot is free */<br />
&nbsp;&nbsp;&nbsp; boolean isFree(int slot) {<br />
&nbsp; return !isAllocated(slot);<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; /** Returns the value of the indicated slot */<br />
&nbsp;&nbsp;&nbsp; FreePhysicalRowId get(int slot) {<br />
&nbsp; if (slots[slot] == null) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; slots[slot] = new FreePhysicalRowId(block, slotToOffset(slot));;<br />
&nbsp; return slots[slot];<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; /** Converts slot to offset */<br />
&nbsp;&nbsp;&nbsp; short slotToOffset(int slot) {<br />
&nbsp; return (short) (O_FREE +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (slot * FreePhysicalRowId.SIZE));<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; /** <br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; Returns first free slot, -1 if no slots are available<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; int getFirstFree() {<br />
&nbsp; for (int i = 0; i &lt; ELEMS_PER_PAGE; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (isFree(i))<br />
&nbsp;&nbsp;&nbsp; return i;<br />
&nbsp; }<br />
&nbsp; return -1;<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; /** <br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; Returns first slot with available size &gt;= indicated size,&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; or -1 if no slots are available.<br />
&nbsp;&nbsp;&nbsp;&nbsp; **/<br />
&nbsp;&nbsp;&nbsp; int getFirstLargerThan(int size) {<br />
&nbsp; for (int i = 0; i &lt; ELEMS_PER_PAGE; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (isAllocated(i) &amp;&amp; get(i).getSize() &gt;= size)<br />
&nbsp;&nbsp;&nbsp; return i;<br />
&nbsp; }<br />
&nbsp; return -1;<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp; 以上主要是进行分配和释放工作，最后两个方法用于查找第一个free的slot和根据size查找slot，很有用，要记住。<br />
&nbsp; 在db中，一个库包含多个table，一个table包含多个记录。一个RecordFile应该就是一个db吧。<br />
&nbsp; <br />
FreePhysicalRowIdPageManager：manages free physical rowid pages and provides methods<br />
&nbsp;to free and allocate physical rowids on a high level.<br />
它有两个成员变量：<br />
&nbsp;&nbsp;&nbsp; // our record file<br />
&nbsp;&nbsp;&nbsp; protected RecordFile _file;</p>
<p>&nbsp;&nbsp;&nbsp; // our page manager<br />
&nbsp;&nbsp;&nbsp; protected PageManager _pageman;</p>
<p>RecordFile和PageManager这两个类前面都有研究，应该不是问题。FreePhysicalRowIdPageManager<br />
只有两个方法：</p>
<p>&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; Returns a free physical rowid of the indicated size, or<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; null if nothing was found.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; Location get( int size )<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; Puts the indicated rowid on the free list<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; void put(Location rowid, int size)<br />
&nbsp;&nbsp;&nbsp; <br />
这里的get方法很重要，从这个方法里面可以看出数据文件的组织方式：</p>
<p>&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; Returns a free physical rowid of the indicated size, or<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; null if nothing was found.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; Location get( int size )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws IOException<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Loop through the free physical rowid list until we find<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // a rowid that's large enough.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Location retval = null;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PageCursor curs = new PageCursor( _pageman, Magic.FREEPHYSIDS_PAGE );</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (curs.next() != 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FreePhysicalRowIdPage fp = FreePhysicalRowIdPage<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .getFreePhysicalRowIdPageView( _file.get( curs.getCurrent() ) );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int slot = fp.getFirstLargerThan( size );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( slot != -1 ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // got one!<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retval = new Location( fp.get( slot ) );</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int slotsize = fp.get( slot ).getSize();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fp.free( slot );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( fp.getCount() == 0 ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // page became empty - free it<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _file.release( curs.getCurrent(), false );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _pageman.free( Magic.FREEPHYSIDS_PAGE, curs.getCurrent() );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _file.release( curs.getCurrent(), true );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return retval;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // no luck, go to next page<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _file.release( curs.getCurrent(), false );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; 当保存数据时，先得到FreePhysicalRowIdPage里面去查有没有合适大小的slot可用。得到合适的slot后，就得到了<br />
&nbsp; FreePhysicalRowId。FreePhysicalRowId持有size信息，这个size前面没有搞清楚，到这里就清楚了，其实是可存放<br />
&nbsp; 数据文件的size。FreePhysicalRowId还持有BlockIo和offset信息，这个被Location使用，get方法最后也是返回Location对象。<br />
&nbsp; <br />
PhysicalRowIdManager：manages physical row ids, and their data.<br />
&nbsp; </p>
<img src ="http://www.blogjava.net/persister/aggbug/270392.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-05-13 13:26 <a href="http://www.blogjava.net/persister/archive/2009/05/13/270392.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDBM学习五（PageManager）</title><link>http://www.blogjava.net/persister/archive/2009/05/12/270216.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Tue, 12 May 2009 07:30:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/05/12/270216.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/270216.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/05/12/270216.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/270216.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/270216.html</trackback:ping><description><![CDATA[<p><strong style="font-size: 14pt">1.PageHeader</strong><br />
PageManager有一个成员变量FileHeader，FileHeader represents a file header. It is a 1:1 representation of the data <br />
that appears in block 0 of a file.FileHeader主要是存储了一些数值：offset和blockid。这些数值是用一个也是RecordFile的第一个BLockIo对象进行存储的，所以它有一个BlockIo的引用。<br />
先看其成员变量：<br />
&nbsp;&nbsp;&nbsp; // offsets<br />
&nbsp;&nbsp;&nbsp; private static final short O_MAGIC = 0; // short magic<br />
&nbsp;&nbsp;&nbsp; private static final short O_LISTS = Magic.SZ_SHORT; // long[2*NLISTS]<br />
&nbsp;&nbsp;&nbsp; private static final int O_ROOTS = <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; O_LISTS + (Magic.NLISTS * 2 * Magic.SZ_LONG);</p>
<p>&nbsp;&nbsp;&nbsp; // my block<br />
&nbsp;&nbsp;&nbsp; private BlockIo block;</p>
<p>O_MAGIC表示FileHeader标示的位置：block.writeShort(O_MAGIC, Magic.FILE_HEADER)向0的位置写入<br />
FileHeader的文件头。</p>
<p>O_LISTS标示LISTS的offset的位置，显然前面是short类型的变量，所以O_LISTS = Magic.SZ_SHORT<br />
O_ROOTS = O_LISTS + (Magic.NLISTS * 2 * Magic.SZ_LONG) Magic.NLISTS等于5，即五个List：<br />
&nbsp;short FREE_PAGE = 0;<br />
&nbsp;short USED_PAGE = 1;<br />
&nbsp;short TRANSLATION_PAGE = 2;<br />
&nbsp;short FREELOGIDS_PAGE = 3;<br />
&nbsp;short FREEPHYSIDS_PAGE = 4;<br />
乘2则表示每隔List需要使用2个Magic.SZ_LONG长度，FIleHeader使用2个Magic.SZ_LONG长度的来记录当前list<br />
中第一个和最后一个block的offset：<br />
&nbsp;&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; Returns the first block of the indicated list<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; long getFirstOf(int list) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return block.readLong(offsetOfFirst(list));<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; Sets the first block of the indicated list<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; void setFirstOf(int list, long value) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; block.writeLong(offsetOfFirst(list), value);<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; 上面的getFirstOf和setFirstOf中输入的参数int list是0~4的值，即上面的5中list的类型值<br />
&nbsp;&nbsp;&nbsp; 即getFirstOf和setFirstOf式获取和设置相应list第一个block顺序号的大小<br />
&nbsp;&nbsp;&nbsp; 而下面是设置最后一个block顺序号的大小。<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; Returns the last block of the indicated list<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; long getLastOf(int list) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return block.readLong(offsetOfLast(list));<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; Sets the last block of the indicated list<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; void setLastOf(int list, long value) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; block.writeLong(offsetOfLast(list), value);<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; /** Returns the offset of the "first" block of the indicated list */<br />
&nbsp;&nbsp;&nbsp; private short offsetOfFirst(int list) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (short) (O_LISTS + (2 * Magic.SZ_LONG * list));<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; /** Returns the offset of the "last" block of the indicated list */<br />
&nbsp;&nbsp;&nbsp; private short offsetOfLast(int list) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (short) (offsetOfFirst(list) + Magic.SZ_LONG);<br />
&nbsp;&nbsp;&nbsp; }</p>
<p><br />
<strong style="font-size: 14pt">2.PageManager</strong><br />
PageManager管理5个LinkedList，每一个type有一个LinkedList，LinkedList里面的元素就是BlockIo对象。这些LinkedList构成了<br />
RecordFile对象。一个PageManager只有一个FileHeader。</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; // our record file<br />
&nbsp;&nbsp;&nbsp; private RecordFile file;<br />
&nbsp;&nbsp;&nbsp; // header data<br />
&nbsp;&nbsp;&nbsp; private FileHeader header;<br />
&nbsp;&nbsp;&nbsp; private BlockIo headerBuf;<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; Creates a new page manager using the indicated record file.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; PageManager(RecordFile file) throws IOException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.file = file;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // check the file header. If the magic is 0, we assume a new<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // file. Note that we hold on to the file header node.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; headerBuf = file.get(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (headerBuf.readShort(0) == 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; header = new FileHeader(headerBuf, true);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; header = new FileHeader(headerBuf, false);<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>PageHeader对BlockIo进行了封装，也就是说LinkedList里面元素实际上市PageHeader对象。但是这是为什么呢？<br />
这个PageHeader主要是做什么的？而且这写是怎么关联起来的呢？下面在PageManager的allocate方法有几行代码<br />
可能帮助理解：<br />
&nbsp;buf = file.get(oldLast);<br />
&nbsp;pageHdr = PageHeader.getView(buf);<br />
&nbsp;pageHdr.setNext(retval);<br />
&nbsp;file.release(oldLast, true);<br />
每一个BlockIo都需要一个PageHeader，这点我真是不大理解，PageHeader，这个Page到底是什么？难道<br />
每一个BlockIo都是一个Page？PageHeader的主要方法就是设置next和previous：</p>
<p>&nbsp;&nbsp;&nbsp; /** Returns the next block. */<br />
&nbsp;&nbsp;&nbsp; long getNext() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; paranoiaMagicOk();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return block.readLong(O_NEXT);<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; /** Sets the next block. */<br />
&nbsp;&nbsp;&nbsp; void setNext(long next) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; paranoiaMagicOk();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; block.writeLong(O_NEXT, next);<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; /** Returns the previous block. */<br />
&nbsp;&nbsp;&nbsp; long getPrev() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; paranoiaMagicOk();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return block.readLong(O_PREV);<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; /** Sets the previous block. */<br />
&nbsp;&nbsp;&nbsp; void setPrev(long prev) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; paranoiaMagicOk();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; block.writeLong(O_PREV, prev);<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>next和previous的id放在O_NEXT和O_PREV的位置。<br />
</p>
<p><br />
<strong style="font-size: 14pt">3.PageHeader的作用<br />
</strong><br />
PageHeader类构造函数有一个参数BlockIo block，注释应为@param block The block that contains the page header<br />
而不是@param block The block that contains the file header。</p>
<p>这基本可以确定，每一个BLockIo都有一个PageHeader，这些PageHeader构成一个LinkedList。<br />
那么怎么得到这些LinkedList里面的对象呢？看一下PageManager这些方法就知道了：<br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; Returns the page following the indicated block<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; long getNext(long block) throws IOException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return PageHeader.getView(file.get(block)).getNext();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } finally {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; file.release(block, false);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; Returns the page before the indicated block<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; long getPrev(long block) throws IOException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return PageHeader.getView(file.get(block)).getPrev();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } finally {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; file.release(block, false);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; Returns the first page on the indicated list.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; long getFirst(short type) throws IOException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return header.getFirstOf(type);<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; Returns the last page on the indicated list.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; long getLast(short type) throws IOException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return header.getLastOf(type);<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; <br />
其实一般不会这么直接获取，而是通过如下的代码进行的：<br />
&nbsp;RecordFile f = new RecordFile(TestRecordFile.testFileName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pm = new PageManager(f);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PageCursor curs = new PageCursor(pm, Magic.USED_PAGE);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; long i = 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (true) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; long cur = curs.next();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (cur == 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //对cur进行操作<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pm.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.close();</p>
<img src ="http://www.blogjava.net/persister/aggbug/270216.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-05-12 15:30 <a href="http://www.blogjava.net/persister/archive/2009/05/12/270216.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDBM学习四（RecordFile） </title><link>http://www.blogjava.net/persister/archive/2009/05/11/270031.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Mon, 11 May 2009 05:36:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/05/11/270031.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/270031.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/05/11/270031.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/270031.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/270031.html</trackback:ping><description><![CDATA[<p><strong style="font-size: 14pt">1.BlockIo状态迁移<br />
</strong>RecordFile是很重要的一个类，几个重要的变量：</p>
<p>&nbsp;final TransactionManager txnMgr;<br />
&nbsp;private final LinkedList free = new LinkedList();<br />
&nbsp;private final HashMap inUse = new HashMap();<br />
&nbsp;private final HashMap dirty = new HashMap();<br />
&nbsp;private final HashMap inTxn = new HashMap();<br />
&nbsp;private RandomAccessFile file;</p>
<p>free是一个LinkedList，FIFO.其他几个维护着BlockIo对象的状态，如果BlockIo对象<br />
从free里面取出来了，那么它的状态就是inUse了，所以RecordFile类get方法最后<br />
会将BlockIo对象放到inUse的Map中：</p>
<p>&nbsp;BlockIo node；<br />
&nbsp;...... <br />
&nbsp;inUse.put(key, node);<br />
&nbsp;node.setClean(); //注意此时node被设置为dirty=false，也就是说BlockIo也有dirty这个指标<br />
&nbsp;return node;</p>
<p>inUse的BlockIo对象如果被修改了，那么它的状态就变成dirty了。由于从inUse中取出的对象是否发生<br />
了改变RecordFile对象不知道，需要调用者调用一个方法release:</p>
<p>&nbsp;/**<br />
&nbsp;*&nbsp; Releases a block.<br />
&nbsp;*<br />
&nbsp;*&nbsp; @param blockid The record number to release.<br />
&nbsp;*&nbsp; @param isDirty If true, the block was modified since the get().<br />
&nbsp;*/<br />
&nbsp;void release(long blockid, boolean isDirty)<br />
&nbsp;throws IOException {<br />
&nbsp;&nbsp;BlockIo node = (BlockIo) inUse.get(new Long(blockid));<br />
&nbsp;&nbsp;if (node == null)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new IOException("bad blockid " + blockid + " on release");<br />
&nbsp;&nbsp;if (!node.isDirty() &amp;&amp; isDirty)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node.setDirty();<br />
&nbsp;&nbsp;release(node);<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;/**<br />
&nbsp;*&nbsp; Releases a block.<br />
&nbsp;*<br />
&nbsp;*&nbsp; @param block The block to release.<br />
&nbsp;*/<br />
&nbsp;void release(BlockIo block) {<br />
&nbsp;&nbsp;Long key = new Long(block.getBlockId());<br />
&nbsp;&nbsp;inUse.remove(key);<br />
&nbsp;&nbsp;if (block.isDirty()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // System.out.println( "Dirty: " + key + block );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dirty.put(key, block);<br />
&nbsp;&nbsp;} else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!transactionsDisabled &amp;&amp; block.isInTransaction()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inTxn.put(key, block);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; free.add(block);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;}<br />
&nbsp;}</p>
<p>release方法输入两个参数，其中一个是isDirty，如果取出来的BlockIo对象修改了<br />
就应该将isDirty置为true，否则修改不会被保存。也就是说修改后，BlockIo对象<br />
被放入map dirty中。<br />
release以后，BlockIo对象可能有三个状态，首先它会从inUse map里面删除。如果<br />
BlockIo对象被修改，则被放入dirty map中。如果没有修改，就有可能放入free map中。</p>
<p>做完修改后，可以关闭这个RecordFile对象。</p>
<p>&nbsp;RecordFile file = new RecordFile( testFileName );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte[] data = file.get( 0 ).getData();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; data[ 14 ] = (byte) 'b';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; file.release( 0, true );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; file.close();</p>
<p>close方法的工作如下：</p>
<p>&nbsp;void close() throws IOException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!dirty.isEmpty()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; commit();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; txnMgr.shutdown();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ......<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; file.close();&nbsp; //此时RandomAccessFile对象close<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; file = null;<br />
&nbsp;&nbsp;&nbsp; &nbsp;}</p>
<p>可以看到close方法里面主要就是commit这个事务：</p>
<p>&nbsp;for (Iterator i = dirty.values().iterator(); i.hasNext(); ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BlockIo node = (BlockIo) i.next();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i.remove();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // System.out.println("node " + node + " map size now " + dirty.size());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (transactionsDisabled) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; long offset = node.getBlockId() * BLOCK_SIZE;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; file.seek(offset);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; file.write(node.getData());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node.setClean();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; free.add(node);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; txnMgr.add(node);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inTxn.put(new Long(node.getBlockId()), node);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>如果transaction被disable，那么每一个节点进行更新，如下：<br />
&nbsp;long offset = node.getBlockId() * BLOCK_SIZE;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; file.seek(offset);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; file.write(node.getData());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node.setClean();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; free.add(node);<br />
从最后一行，BlockIo对象node的状态重新变为free。以上状态的变化是如下一个循环：<br />
free -&gt; inUse -&gt; dirty -&gt; inTxn -&gt; free<br />
<br />
<strong style="font-size: 14pt">2.BlockIo的获取</strong><br />
RecordFile对应两个文件，一个是.db文件，另一个是.lg文件。缓存对象即BlockIo是操作<br />
的最小单元，在get方法中，如果指定的blockid不在inTxn,dirty和free中，那么通过<br />
getNewNode(blockid)得到一个新的BlockIo对象，如果blockid在有效范围内（这个判断是通过<br />
计算offset得到的，offset=blockid*BLOCK_SIZE，offset小于.db文件的大小，那说明blockid对应<br />
的数据块在文件内），那么就从.db文件中读取去blockid对应的数据库。如果不在有效范围内，那么<br />
数据块就是cleanData的copy，即A block of clean data。</p>
<p>&nbsp;// get a new node and read it from the file<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node = getNewNode(blockid);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; long offset = blockid * BLOCK_SIZE;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (file.length() &gt; 0 &amp;&amp; offset &lt;= file.length()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; read(file, offset, node.getData(), BLOCK_SIZE);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.arraycopy(cleanData, 0, node.getData(), 0, BLOCK_SIZE);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inUse.put(key, node);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node.setClean();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return node;</p>
<p>这里getNewNode()方法如下：<br />
&nbsp;&nbsp;&nbsp; private BlockIo getNewNode(long blockid)<br />
&nbsp;&nbsp;&nbsp; throws IOException <br />
&nbsp;&nbsp;&nbsp; {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BlockIo retval = null;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!free.isEmpty()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retval = (BlockIo) free.removeFirst();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (retval == null)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retval = new BlockIo(0, new byte[BLOCK_SIZE]);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retval.setBlockId(blockid);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retval.setView(null);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return retval;<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; <br />
getNewNode()不是直接new BlockIo()，而是从free中取，free中的<br />
BlockIo对象没有被使用，则直接利用，采取的方式是Least Recently Used策略。BlockIo实现了自定义的Externalizable<br />
序列化：<br />
&nbsp;&nbsp;&nbsp; // implement externalizable interface<br />
&nbsp;&nbsp;&nbsp; public void readExternal(ObjectInput in)<br />
&nbsp;&nbsp;&nbsp; throws IOException, ClassNotFoundException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; blockId = in.readLong();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int length = in.readInt();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; data = new byte[length];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in.readFully(data);<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; // implement externalizable interface<br />
&nbsp;&nbsp;&nbsp; public void writeExternal(ObjectOutput out) throws IOException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.writeLong(blockId);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.writeInt(data.length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.write(data);<br />
&nbsp;&nbsp;&nbsp; }<br />
</p>
<p><br />
<strong style="font-size: 14pt">3.TransactionManager的事务处理</strong><br />
<br />
序列化用在事务这块，如果没有启动事务，RecordFile直接写到.db文件中，不会进行序列化操作。</p>
<p>RecordFile演示了事务的操作：<br />
&nbsp;final TransactionManager txnMgr;<br />
&nbsp;......<br />
&nbsp;txnMgr = new TransactionManager(this);<br />
&nbsp;......<br />
&nbsp;if (!transactionsDisabled) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; txnMgr.start();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ......<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!transactionsDisabled)<br />
&nbsp;&nbsp;&nbsp;&nbsp; txnMgr.add(node);</p>
<p>&nbsp;......<br />
&nbsp;if (!transactionsDisabled) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; txnMgr.commit();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ......<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; txnMgr.shutdown();</p>
<p>以上是一个完整的事务过程，下面对以上过程发生的操作深入阐述：</p>
<p>TransactionManager(this)以RecordFile作为参数进行构造：<br />
&nbsp;TransactionManager(RecordFile owner) throws IOException {<br />
&nbsp;&nbsp;&nbsp;&nbsp; this.owner = owner;<br />
&nbsp;&nbsp;&nbsp;&nbsp; recover();<br />
&nbsp;&nbsp;&nbsp;&nbsp; open();<br />
&nbsp;}</p>
<p>TransactionManager持有RecordFile的引用，然后进行recover和open操作。recover主要是<br />
对log file进行操作，如果有事务没有执行，那么执行事务将log file中的数据写到.db文件中<br />
并且对RecordFile进行sync()操作，最后把log file删除。</p>
<p>&nbsp;&nbsp;&nbsp; private void recover() throws IOException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String logName = makeLogName();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File logFile = new File(logName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!logFile.exists())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (logFile.length() == 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logFile.delete();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FileInputStream fis = new FileInputStream(logFile);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ObjectInputStream ois = new ObjectInputStream(fis);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ois.readShort() != Magic.LOGFILE_HEADER)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new Error("Bad magic on log file");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (IOException e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // corrupted/empty logfile<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logFile.delete();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (true) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ArrayList blocks = null;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; blocks = (ArrayList) ois.readObject();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (ClassNotFoundException e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new Error("Unexcepted exception: " + e);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (IOException e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // corrupted logfile, ignore rest of transactions<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synchronizeBlocks(blocks.iterator(), false);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // ObjectInputStream must match exactly each<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // ObjectOutputStream created during writes<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ois = new ObjectInputStream(fis);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (IOException e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // corrupted logfile, ignore rest of transactions<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; owner.sync();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logFile.delete();<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>open的操作相对简单很多，只是进行一些初始化赋值工作：<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; /** Opens the log file */<br />
&nbsp;&nbsp;&nbsp; private void open() throws IOException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fos = new FileOutputStream(makeLogName());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oos = new ObjectOutputStream(fos);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oos.writeShort(Magic.LOGFILE_HEADER);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oos.flush();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; curTxn = -1;<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>下一步就是start这个txnMgr了：<br />
&nbsp;&nbsp;&nbsp; void start() throws IOException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; curTxn++;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (curTxn == _maxTxns) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synchronizeLogFromMemory();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; curTxn = 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; txns[curTxn] = new ArrayList();<br />
&nbsp;&nbsp;&nbsp; }<br />
start的时候就将当前事务数增加1，如果当前事务数等于设置的最大事务数，就进行sync处理。<br />
sync处理的代码如下：</p>
<p>&nbsp;/** Synchs in-core transactions to data file and opens a fresh log */<br />
&nbsp;&nbsp;&nbsp; private void synchronizeLogFromMemory() throws IOException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; close();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TreeSet blockList = new TreeSet( new BlockIoComparator() );</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int numBlocks = 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int writtenBlocks = 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; _maxTxns; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (txns[i] == null)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Add each block to the blockList, replacing the old copy of this<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // block if necessary, thus avoiding writing the same block twice<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (Iterator k = txns[i].iterator(); k.hasNext(); ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BlockIo block = (BlockIo)k.next();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( blockList.contains( block ) ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; block.decrementTransactionCount();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; writtenBlocks++;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boolean result = blockList.add( block );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; numBlocks++;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; txns[i] = null;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Write the blocks from the blockList to disk<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synchronizeBlocks(blockList.iterator(), true);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; owner.sync();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; open();<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>sync的主要操作就是synchronizeBlocks操作：<br />
&nbsp;&nbsp;&nbsp; private void synchronizeBlocks(Iterator blockIterator, boolean fromCore)<br />
&nbsp;&nbsp;&nbsp; throws IOException <br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // write block vector elements to the data file.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while ( blockIterator.hasNext() ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BlockIo cur = (BlockIo)blockIterator.next();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; owner.synch(cur);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (fromCore) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cur.decrementTransactionCount();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!cur.isInTransaction()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; owner.releaseFromTransaction(cur, true);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }</p>
<p><br />
接下来的操作txnMgr.add(node)：<br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; Indicates the block is part of the transaction.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; void add(BlockIo block) throws IOException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; block.incrementTransactionCount();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; txns[curTxn].add(block);<br />
&nbsp;&nbsp;&nbsp; }<br />
这个操作很简单，就是将BlockIo对象放入到当前事务的ArrayList当中。之后commit操作：</p>
<p>&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; Commits the transaction to the log file.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; void commit() throws IOException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oos.writeObject(txns[curTxn]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sync();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // set clean flag to indicate blocks have been written to log<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setClean(txns[curTxn]);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // open a new ObjectOutputStream in order to store<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // newer states of BlockIo<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oos = new ObjectOutputStream(fos);<br />
&nbsp;&nbsp;&nbsp; }&nbsp;<br />
&nbsp;&nbsp;&nbsp; <br />
最后的操作就是txnMgr.shutdown()：</p>
<p>&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; Shutdowns the transaction manager. Resynchronizes outstanding<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; logs.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; void shutdown() throws IOException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synchronizeLogFromMemory();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; close();<br />
&nbsp;&nbsp;&nbsp; }</p>
<img src ="http://www.blogjava.net/persister/aggbug/270031.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-05-11 13:36 <a href="http://www.blogjava.net/persister/archive/2009/05/11/270031.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java对象序列化二</title><link>http://www.blogjava.net/persister/archive/2009/05/08/269529.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Fri, 08 May 2009 01:29:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/05/08/269529.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/269529.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/05/08/269529.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/269529.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/269529.html</trackback:ping><description><![CDATA[<p><span style="font-size: 14pt;"><span style="font-size: 12pt;">前面写了一个<a href="http://www.blogjava.net/persister/archive/2006/09/22/71359.html">序列化的文章</a>，这次重新整理一下。</span><br />
</span></p>
<p><strong style="font-size: 14pt;">1.Serialize概念</strong><br />
Java的对象序列化就是将那些实现了Serializable接口的对象转换成一个字节序列。并能够<br />
在以后将这个字节完全恢复为原来的对象。<br />
对象序列化的概念加入到语言当中就是为了支持两种主要特性</p>
<p>一是Java的远程方法调用（Remote Method Invocation, RMI）。当向远程对象发送消息时，<br />
需要通过序列化来传输参数和返回值。<br />
<br />
二是Javabean对象序列化。有些服务器通过将所有的SESSION 数据（包括BEAN）写入磁盘来支持任意长的SESSION生命期，即使服务器停机也不会丢失。当服务器重新启动后，串行化的数据被恢复。同样的理由，在重负载的站点上支持服务器分簇的环境中，许多服务器通过串行化来复制SESSION。如果你的BEAN不支持串行化，服务器就不能正确地保存和传输类。</p>
<p><span style="color: red;">只要对象实现了Serializable接口，对象的序列化处理就会非常简单。<br />
</span><strong style="font-size: 14pt;">2.Serialize方法<br />
</strong>要序列化一个对象，首先要创建某些OutputStream对象，然后将其封装在一个ObjectOutputStream对象内。<br />
这时，只需要调用writeObject()即可将对象序列化，并将其发送给OutputStream。反之，将一个序列化对象还原为一个对象，需要将一个InputStream封装在ObjectInputStream内，然后调用readObject()。<br />
OutputStream和InputStream常用的是ByteArrayOutputStream/FileOutputStream和ByteArrayInputStream/FileInputStream。</p>
<p>下面两个类以ByteArray方式实现序列化：</p>
<p>public final class Serialization<br />
{</p>
<p>&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Serialize the object into a byte array.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public static byte[] serialize( Object obj )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws IOException<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ByteArrayOutputStream&nbsp; baos;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ObjectOutputStream&nbsp;&nbsp;&nbsp;&nbsp; oos;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; baos = new ByteArrayOutputStream();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oos = new ObjectOutputStream( baos );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oos.writeObject( obj );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oos.close();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return baos.toByteArray();<br />
&nbsp;&nbsp;&nbsp; }</p>
<p><br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Deserialize an object from a byte array<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public static Object deserialize( byte[] buf )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws ClassNotFoundException, IOException<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ByteArrayInputStream&nbsp; bais;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ObjectInputStream&nbsp;&nbsp;&nbsp;&nbsp; ois;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bais = new ByteArrayInputStream( buf );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ois = new ObjectInputStream( bais );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ois.readObject();<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>}</p>
<p>public class DefaultSerializer<br />
&nbsp;&nbsp;&nbsp; implements Serializer<br />
{</p>
<p>&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; public static final DefaultSerializer INSTANCE = new DefaultSerializer();<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Construct a DefaultSerializer.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public DefaultSerializer()<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // no op<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Serialize the content of an object into a byte array.<br />
&nbsp;&nbsp;&nbsp;&nbsp; *<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @param obj Object to serialize<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @return a byte array representing the object's state<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp;&nbsp; public byte[] serialize( Object obj )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws IOException<br />
&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Serialization.serialize( obj );<br />
&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Deserialize the content of an object from a byte array.<br />
&nbsp;&nbsp;&nbsp;&nbsp; *<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @param serialized Byte array representation of the object<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @return deserialized object<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp;&nbsp; public Object deserialize( byte[] serialized )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws IOException<br />
&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Serialization.deserialize( serialized );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch ( ClassNotFoundException except ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new WrappedRuntimeException( except );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>}</p>
<p>File方式的序列化大致如下：</p>
<p>ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(out.txt));<br />
out.writeObject(obj);<br />
out.close();</p>
<p>ObjectInputStream in = new ObjectInputStream(new FileInputStream(out.txt));<br />
Object obj = (Object)in.readObject();<br />
in.close();<br />
</p>
<p><strong style="font-size: 14pt;">3.Serialize定制</strong><br />
<br />
缺省的序列化机制并不难操纵，如果有特殊的需求那又该怎么办？例如，也许要考虑特殊的安全问题，而且<br />
你不希望对象的某一部分被序列化；或者一个对象被还原后，某子对象需要重新创建，从而不需要将该子对象<br />
序列化。在这样的特殊情况下，可通过实现Externalizable接口来对序列化过程进行控制。这个Externalizable<br />
接口继承了Serializable接口，同时增加了两个方法：writeExternal(ObjectOutput out)和readExternal(ObjectInput in)</p>
<p>Serializable对象完全以它存储的二进制位为基础来构造，而不用调用构造器。而对于一个Externalizable对象<br />
缺省构造器都会被调用，然后调用readExternal()。下面列子中，如果Blip3()构造器注释掉，程序会报错：no valid constructor</p>
<p><br />
// Reconstructing an externalizable object.<br />
// From 'Thinking in Java, 3rd ed.' (c) Bruce Eckel 2002<br />
// www.BruceEckel.com. See copyright notice in CopyRight.txt.<br />
import com.bruceeckel.simpletest.*;<br />
import java.io.*;<br />
import java.util.*;</p>
<p>public class Blip3 implements Externalizable {<br />
&nbsp; private static Test monitor = new Test();<br />
&nbsp; private int i;<br />
&nbsp; private String s; // No initialization<br />
&nbsp; public Blip3() {<br />
&nbsp;&nbsp;&nbsp; System.out.println("Blip3 Constructor");<br />
&nbsp;&nbsp;&nbsp; // s, i not initialized<br />
&nbsp; }<br />
&nbsp; public Blip3(String x, int a) {<br />
&nbsp;&nbsp;&nbsp; System.out.println("Blip3(String x, int a)");<br />
&nbsp;&nbsp;&nbsp; s = x;<br />
&nbsp;&nbsp;&nbsp; i = a;<br />
&nbsp;&nbsp;&nbsp; // s &amp; i initialized only in nondefault constructor.<br />
&nbsp; }<br />
&nbsp; public String toString() { return s + i; }<br />
&nbsp; public void writeExternal(ObjectOutput out)<br />
&nbsp; throws IOException {<br />
&nbsp;&nbsp;&nbsp; System.out.println("Blip3.writeExternal");<br />
&nbsp;&nbsp;&nbsp; // You must do this:<br />
&nbsp;&nbsp;&nbsp; out.writeObject(s);<br />
&nbsp;&nbsp;&nbsp; out.writeInt(i);<br />
&nbsp; }<br />
&nbsp; public void readExternal(ObjectInput in)<br />
&nbsp; throws IOException, ClassNotFoundException {<br />
&nbsp;&nbsp;&nbsp; System.out.println("Blip3.readExternal");<br />
&nbsp;&nbsp;&nbsp; // You must do this:<br />
&nbsp;&nbsp;&nbsp; s = (String)in.readObject();<br />
&nbsp;&nbsp;&nbsp; i = in.readInt();<br />
&nbsp; }<br />
&nbsp; public static void main(String[] args)<br />
&nbsp; throws IOException, ClassNotFoundException {<br />
&nbsp;&nbsp;&nbsp; System.out.println("Constructing objects:");<br />
&nbsp;&nbsp;&nbsp; Blip3 b3 = new Blip3("A String ", 47);<br />
&nbsp;&nbsp;&nbsp; System.out.println(b3);<br />
&nbsp;&nbsp;&nbsp; ObjectOutputStream o = new ObjectOutputStream(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new FileOutputStream("Blip3.out"));<br />
&nbsp;&nbsp;&nbsp; System.out.println("Saving object:");<br />
&nbsp;&nbsp;&nbsp; o.writeObject(b3);<br />
&nbsp;&nbsp;&nbsp; o.close();<br />
&nbsp;&nbsp;&nbsp; // Now get it back:<br />
&nbsp;&nbsp;&nbsp; ObjectInputStream in = new ObjectInputStream(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new FileInputStream("Blip3.out"));<br />
&nbsp;&nbsp;&nbsp; System.out.println("Recovering b3:");<br />
&nbsp;&nbsp;&nbsp; b3 = (Blip3)in.readObject();<br />
&nbsp;&nbsp;&nbsp; System.out.println(b3);<br />
&nbsp;&nbsp;&nbsp; monitor.expect(new String[] {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Constructing objects:",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Blip3(String x, int a)",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "A String 47",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Saving object:",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Blip3.writeExternal",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Recovering b3:",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Blip3 Constructor",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Blip3.readExternal",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "A String 47"<br />
&nbsp;&nbsp;&nbsp; });<br />
&nbsp; }<br />
}</p>
<p>&nbsp;</p>
<img src ="http://www.blogjava.net/persister/aggbug/269529.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-05-08 09:29 <a href="http://www.blogjava.net/persister/archive/2009/05/08/269529.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDBM学习三（RecordManager）</title><link>http://www.blogjava.net/persister/archive/2009/05/05/269034.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Tue, 05 May 2009 09:50:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/05/05/269034.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/269034.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/05/05/269034.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/269034.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/269034.html</trackback:ping><description><![CDATA[<p>JDBM中提供了一个接口RecordManager，用于对记录进行操作：<br />
</p>
<p>&nbsp; public abstract long insert( Object obj )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws IOException;</p>
<p>&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; Inserts a new record using a custom serializer.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public abstract long insert( Object obj, Serializer serializer )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws IOException;<br />
<br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; Deletes a record.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public abstract void delete( long recid )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws IOException;</p>
<p><br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; Updates a record using standard java object serialization.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public abstract void update( long recid, Object obj )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws IOException;</p>
<p><br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; Updates a record using a custom serializer.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public abstract void update( long recid, Object obj, Serializer serializer )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws IOException;</p>
<p>&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; Fetches a record using standard java object serialization.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public abstract Object fetch( long recid )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws IOException;</p>
<p><br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; Fetches a record using a custom serializer.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public abstract Object fetch( long recid, Serializer serializer )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws IOException;</p>
<p><br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp; Closes the record manager.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public abstract void close()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws IOException;</p>
<br />
具体的实现类一共两个：BaseRecordManager和CacheRecordManager，后者是前者的Cache。BaseRecordManager用于将缓存对象序列化到文件系统中，即缓存对象管理主要是文件读取方面的操作，而CacheRecordManager<br />
对读取的文件进行了缓存，较少IO的次数提高效率。<br />
<br />
BaseRecordManager<br />
<br />
BaseRecordManager有四个主要的变量<br />
<p>&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Underlying record file.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; private RecordFile _file;<br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Physical row identifier manager.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; private PhysicalRowIdManager _physMgr;<br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Logigal to Physical row identifier manager.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; private LogicalRowIdManager _logMgr;<br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Page manager.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; private PageManager _pageman;</p>
<br />
没有看其实现代码，但是从其构造函数可以看出一些端倪：<br />
&nbsp;&nbsp;&nbsp; public BaseRecordManager( String filename )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws IOException<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _file = new RecordFile( filename );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _pageman = new PageManager( _file );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _physMgr = new PhysicalRowIdManager( _file, _pageman );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _logMgr = new LogicalRowIdManager( _file, _pageman );<br />
&nbsp;&nbsp;&nbsp; }<br />
jdbm.recman主要都是关于Page,PhysicalRow和LogicalRow这些相关类。<br />
<br />
   <img src ="http://www.blogjava.net/persister/aggbug/269034.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-05-05 17:50 <a href="http://www.blogjava.net/persister/archive/2009/05/05/269034.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SoftReference,WeakReference&amp;WeakHashMap</title><link>http://www.blogjava.net/persister/archive/2009/05/05/268974.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Tue, 05 May 2009 06:53:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/05/05/268974.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/268974.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/05/05/268974.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/268974.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/268974.html</trackback:ping><description><![CDATA[<p>zz http://java.chinaitlab.com/oop/716371.html<br />
<br />
在JDK1.2以前的版本中，当一个对象不被任何变量引用，那么程序就无法再使用这个对象。也就是说，只有对象处于可触及状态，程序才能使用它。这 就像在日常生活中，从商店购买了某样物品后，如果有用，就一直保留它，否则就把它扔到垃圾箱，由清洁工人收走。一般说来，如果物品已经被扔到垃圾箱，想再 把它捡回来使用就不可能了。<br />
<br />
&nbsp;&nbsp;&nbsp; 但有时候情况并不这么简单，你可能会遇到类似鸡肋一样的物品，食之无味，弃之可惜。这种物品现在已经无用了，保留它会占空间，但是立刻扔掉它也不划算，因 为也许将来还会派用场。对于这样的可有可无的物品，一种折衷的处理办法是：如果家里空间足够，就先把它保留在家里，如果家里空间不够，即使把家里所有的垃 圾清除，还是无法容纳那些必不可少的生活用品，那么再扔掉这些可有可无的物品。<br />
<br />
&nbsp;&nbsp;&nbsp; 从JDK1.2版本开始，把对象的引用分为四种级别，从而使程序能更加灵活的控制对象的生命周期。这四种级别由高到低依次为：强引用、软引用、弱引用和虚引用。 </p>
<p><br />
<strong>1．强引用</strong><br />
&nbsp;&nbsp;&nbsp; 本章前文介绍的引用实际上都是强引用，这是使用最普遍的引用。如果一个对象具有强引用，那就类似于必不可少的生活用品，垃圾回收器绝不会回收它。当内存空 间不足，<a class="channel_keylink" href="http://java.chinaitlab.com/" target="_blank">Java</a>虚拟机宁愿抛出OutOfMemoryError错误，使程序异常终止，也不会靠随意回收具有强引用的对象来解决内存不足问题。 </p>
<p><br />
<strong>2．软引用（SoftReference）</strong><br />
</p>
<p>&nbsp;&nbsp;&nbsp; 如果一个对象只具有软引用，那就类似于可有可物的生活用品。如果内存空间足够，垃圾回收器就不会回收它，如果内存空间不足了，就会回收这些对象的内存。只要垃圾回收器没有回收它，该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。<br />
软引用可以和一个引用队列（ReferenceQueue）联合使用，如果软引用所引用的对象被垃圾回收，<a class="channel_keylink" href="http://java.chinaitlab.com/" target="_blank">Java</a>虚拟机就会把这个软引用加入到与之关联的引用队列中。<br />
</p>
<p><strong>3．弱引用（WeakReference）</strong><br />
&nbsp;&nbsp;&nbsp; 如果一个对象只具有弱引用，那就类似于可有可物的生活用品。弱引用与软引用的区别在于：只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它 所管辖的内存区域的过程中，一旦发现了只具有弱引用的对象，不管当前内存空间足够与否，都会回收它的内存。不过，由于垃圾回收器是一个优先级很低的线程， 因此不一定会很快发现那些只具有弱引用的对象。 <br />
弱引用可以和一个引用队列（ReferenceQueue）联合使用，如果弱引用所引用的对象被垃圾回收，Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。</p>
<p><br />
<strong>4．虚引用（PhantomReference）</strong><br />
&nbsp;&nbsp;&nbsp; "虚引用"顾名思义，就是形同虚设，与其他几种引用都不同，虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用，那么它就和没有任何引用一样，在任何时候都可能被垃圾回收。<br />
虚引用主要用来跟踪对象被垃圾回收的活动。虚引用与软引用和弱引用的一个区别在于：虚引用必须和引用队列（ReferenceQueue）联合使用。当垃 圾回收器准备回收一个对象时，如果发现它还有虚引用，就会在回收对象的内存之前，把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是 否已经加入了虚引用，来了解</p>
<p>&nbsp;&nbsp;&nbsp; 被引用的对象是否将要被垃圾回收。程序如果发现某个虚引用已经被加入到引用队列，那么就可以在所引用的对象的内存被回收之前采取必要的行动。<br />
</p>
<p>&nbsp;&nbsp;&nbsp; 在本书中，"引用"既可以作为动词，也可以作为名词，读者应该根据上下文来区分"引用"的含义。<br />
在java.lang.ref包中提供了三个类：SoftReference类、WeakReference类和PhantomReference类，它 们分别代表软引用、弱引用和虚引用。ReferenceQueue类表示引用队列，它可以和这三种引用类联合使用，以便跟踪Java虚拟机回收所引用的对 象的活动。以下程序创建了一个String对象、ReferenceQueue对象和WeakReference对象：<br />
</p>
<p><font color="#0000ff">//创建一个强引用<br />
String str = new String("hello"); </font></p>
<p><font color="#0000ff">//创建引用队列, &lt;String&gt;为范型标记，表明队列中存放String对象的引用<br />
ReferenceQueue&lt;String&gt; rq = new ReferenceQueue&lt;String&gt;(); </font></p>
<p><font color="#0000ff">//创建一个弱引用，它引用"hello"对象，并且与rq引用队列关联<br />
//&lt;String&gt;为范型标记，表明WeakReference会弱引用String对象<br />
WeakReference&lt;String&gt; wf = new WeakReference&lt;String&gt;(str, rq);</font><br />
</p>
<p>以上程序代码执行完毕，内存中引用与对象的关系如图11-10所示。<br />
</p>
<p><img alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200703/20070320103110900.gif" width="350" height="247" /></p>
<p>图11-10 "hello"对象同时具有强引用和弱引用<br />
<br />
在图11-10中，带实线的箭头表示强引用，带虚线的箭头表示弱引用。从图中可以看出，此时"hello"对象被str强引用，并且被一个WeakReference对象弱引用，因此"hello"对象不会被垃圾回收。<br />
在以下程序代码中，把引用"hello"对象的str变量置为null，然后再通过WeakReference弱引用的get()方法获得"hello"对象的引用：<br />
</p>
<p><font color="#0000ff">String str = new String("hello"); //① <br />
ReferenceQueue&lt;String&gt; rq = new ReferenceQueue&lt;String&gt;(); //② <br />
WeakReference&lt;String&gt; wf = new WeakReference&lt;String&gt;(str, rq); //③</font></p>
<p><font color="#0000ff">str=null; //④取消"hello"对象的强引用<br />
String str1=wf.get(); //⑤假如"hello"对象没有被回收，str1引用"hello"对象</font></p>
<p><font color="#0000ff">//假如"hello"对象没有被回收，rq.poll()返回null<br />
Reference&lt;? extends String&gt; ref=rq.poll(); //⑥</font></p>
<p><font color="#0000ff"><br />
</font>&nbsp;&nbsp;&nbsp; 执行完以上第④行后，内存中引用与对象的关系如图11-11所示，此 时"hello"对象仅仅具有弱引用，因此它有可能被垃圾回收。假如它还没有被垃圾回收，那么接下来在第⑤行执行wf.get()方法会返回 "hello"对象的引用，并且使得这个对象被str1强引用。再接下来在第⑥行执行rq.poll()方法会返回null，因为此时引用队列中没有任何 引用。ReferenceQueue的poll()方法用于返回队列中的引用，如果没有则返回null。</p>
<p><img alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200703/20070320103110764.gif" width="350" height="247" /><br />
图11-11 "hello"对象只具有弱引用<br />
</p>
<p>&nbsp;&nbsp;&nbsp; 在以下程序代码中，执行完第④行后，"hello"对象仅仅具有弱引用。接下来两次调用System.gc()方法，催促垃圾回收器工作，从而提高 "hello"对象被回收的可能性。假如"hello"对象被回收，那么WeakReference对象的引用被加入到ReferenceQueue中， 接下来wf.get()方法返回null，并且rq.poll()方法返回WeakReference对象的引用。图11-12显示了执行完第⑧行后内存 中引用与对象的关系。 <br />
</p>
<p><font color="#0000ff">String str = new String("hello"); //①<br />
ReferenceQueue&lt;String&gt; rq = new ReferenceQueue&lt;String&gt;(); //② <br />
WeakReference&lt;String&gt; wf = new WeakReference&lt;String&gt;(str, rq); //③<br />
str=null; //④</font></p>
<p><font color="#0000ff">//两次催促垃圾回收器工作，提高"hello"对象被回收的可能性<br />
System.gc(); //⑤<br />
System.gc(); //⑥<br />
String str1=wf.get(); //⑦ 假如"hello"对象被回收，str1为null<br />
Reference&lt;? extends String&gt; ref=rq.poll(); //⑧</font></p>
<p><img alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200703/20070320103110790.gif" width="393" height="239" /><br />
图11-12 "hello"对象被垃圾回收，弱引用被加入到引用队列</p>
<br />
在以下例程11-15的References类中，依次创建了10个软引用、10个弱引用和10个虚引用，它们各自引用一个Grocery对象。从程序运 行时的打印结果可以看出，虚引用形同虚设，它所引用的对象随时可能被垃圾回收，具有弱引用的对象拥有稍微长的生命周期，当垃圾回收器执行回收操作时，有可 能被垃圾回收，具有软引用的对象拥有较长的生命周期，但在Java虚拟机认为内存不足的情况下，也会被垃圾回收。<br />
<p><font color="#0000ff">例程11-15 References.java<br />
import java.lang.ref.*;<br />
import java.util.*;</font></p>
<p><font color="#0000ff">class Grocery{<br />
private static final int SIZE = 10000;<br />
//属性d使得每个Grocery对象占用较多内存，有80K左右<br />
private double[] d = new double[SIZE]; <br />
private String id;<br />
public Grocery(String id) { this.id = id; }<br />
public String toString() { return id; }<br />
public void finalize() {<br />
System.out.println("Finalizing " + id);<br />
}<br />
}</font></p>
<p><font color="#0000ff">public class References {<br />
private static ReferenceQueue&lt;Grocery&gt; rq = new ReferenceQueue&lt;Grocery&gt;();<br />
public static void checkQueue() {<br />
Reference&lt;? extends Grocery&gt; inq = rq.poll(); //从队列中取出一个引用<br />
if(inq != null)<br />
System.out.println("In queue: "+inq+" : "+inq.get());<br />
}</font></p>
<p><font color="#0000ff">public static void main(String[] args) {<br />
final int size=10;<br />
<br />
//创建10个Grocery对象以及10个软引用<br />
Set&lt;SoftReference&lt;Grocery&gt;&gt; sa = new HashSet&lt;SoftReference&lt;Grocery&gt;&gt;();<br />
for(int i = 0; i &lt; size; i++) {<br />
SoftReference&lt;Grocery&gt; ref=<br />
new SoftReference&lt;Grocery&gt;(new Grocery("Soft " + i), rq);<br />
System.out.println("Just created: " +ref.get());<br />
sa.add(ref);<br />
}<br />
System.gc();<br />
checkQueue();</font></p>
<p><font color="#0000ff">//创建10个Grocery对象以及10个弱引用<br />
Set&lt;WeakReference&lt;Grocery&gt;&gt; wa = new HashSet&lt;WeakReference&lt;Grocery&gt;&gt;();<br />
for(int i = 0; i &lt; size; i++) {<br />
WeakReference&lt;Grocery&gt; ref=<br />
new WeakReference&lt;Grocery&gt;(new Grocery("Weak " + i), rq);<br />
System.out.println("Just created: " +ref.get());<br />
wa.add(ref); <br />
}<br />
System.gc();<br />
checkQueue();</font></p>
<p><font color="#0000ff">//创建10个Grocery对象以及10个虚引用<br />
Set&lt;PhantomReference&lt;Grocery&gt;&gt; pa = new HashSet&lt;PhantomReference&lt;Grocery&gt;&gt;();<br />
for(int i = 0; i &lt; size; i++) {<br />
PhantomReference&lt;Grocery&gt;ref = <br />
new PhantomReference&lt;Grocery&gt;(new Grocery("Phantom " + i), rq);<br />
System.out.println("Just created: " +ref.get());<br />
pa.add(ref);<br />
}<br />
System.gc();<br />
checkQueue();<br />
}<br />
}</font></p>
<br />
在Java集合中有一种特殊的Map类型：WeakHashMap， 在这种Map中存放了键对象的弱引用，当一个键对象被垃圾回收，那么相应的值对象的引用会从Map中删除。WeakHashMap能够节约<a class="channel_keylink" href="http://www.storworld.com/" target="_blank">存储</a>空间，可用 来缓存那些非必须存在的数据。关于Map接口的一般用法，可参见本书第15章的15.4节（Map）。<br />
<p>&nbsp;&nbsp;&nbsp; 以下例程11-16的MapCache类的main()方法创建了一个WeakHashMap对象，它存放了一组Key对象的弱引用，此外main()方法还创建了一个数组对象，它存放了部分Key对象的强引用。<br />
</p>
<p><font color="#0000ff">例程11-16 MapCache.java<br />
import java.util.*;<br />
import java.lang.ref.*;<br />
<br />
class Key {<br />
String id;<br />
public Key(String id) { this.id = id; }<br />
public String toString() { return id; }<br />
public int hashCode() { <br />
return id.hashCode();<br />
}<br />
public boolean equals(Object r) {<br />
return (r instanceof Key)<br />
&amp;&amp; id.equals(((Key)r).id);<br />
}<br />
public void finalize() {<br />
System.out.println("Finalizing Key "+ id);<br />
}<br />
}</font></p>
<p><font color="#0000ff">class Value {<br />
String id;<br />
public Value(String id) { this.id = id; }<br />
public String toString() { return id; }<br />
public void finalize() {<br />
System.out.println("Finalizing Value "+id);<br />
}<br />
}</font></p>
<p><font color="#0000ff">public class MapCache {<br />
public static void main(String[] args) throws Exception{<br />
int size = 1000;<br />
// 或者从命令行获得size的大小<br />
if(args.length &gt; 0)size = Integer.parseInt(args[0]); </font></p>
<p><font color="#0000ff">Key[] keys = new Key[size]; //存放键对象的强引用<br />
WeakHashMap&lt;Key,Value&gt; whm = new WeakHashMap&lt;Key,Value&gt;();<br />
for(int i = 0; i &lt; size; i++) {<br />
Key k = new Key(Integer.toString(i));<br />
Value v = new Value(Integer.toString(i));<br />
if(i % 3 == 0) keys[i] = k; //使Key对象持有强引用 <br />
whm.put(k, v); //使Key对象持有弱引用<br />
}<br />
//催促垃圾回收器工作<br />
System.gc();<br />
<br />
//把CPU让给垃圾回收器线程<br />
Thread.sleep(8000);<br />
}<br />
}<br />
</font></p>
<p>以上程序的部分打印结果如下：<br />
</p>
<p>Finalizing Key 998<br />
Finalizing Key 997<br />
Finalizing Key 995<br />
Finalizing Key 994<br />
Finalizing Key 992<br />
Finalizing Key 991<br />
Finalizing Key 989<br />
Finalizing Key 988<br />
Finalizing Key 986<br />
Finalizing Key 985<br />
Finalizing Key 983<br />
</p>
<p>&nbsp;&nbsp;&nbsp; 从打印结果可以看出，当执行System.gc()方法后，垃圾回收器只会回收那些仅仅持有弱引用的Key对象。id可以被3整数的Key对象持有强引用，因此不会被回收。</p>
<img src ="http://www.blogjava.net/persister/aggbug/268974.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-05-05 14:53 <a href="http://www.blogjava.net/persister/archive/2009/05/05/268974.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDBM学习二（CachePolicy）</title><link>http://www.blogjava.net/persister/archive/2009/05/05/268955.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Tue, 05 May 2009 05:33:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/05/05/268955.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/268955.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/05/05/268955.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/268955.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/268955.html</trackback:ping><description><![CDATA[CachePolicy在JDBM有两种现成的实现，一个是MRU(Most Recently Used)，另一个是SoftCache。<br />
MRU用Hashtable来保存缓存对象，每一个对象都维护它的next和previous对象，这样形成一个双向链表。之所以采用Hashtable，应该是考虑同步的问题。<br />
<br />
MRU的原则就是最多使用的缓存对象放在链表的最末尾，最少使用的缓存对象放在链表的头部。新加的缓存对象都是放在尾部，如果有size的限制，那么头部的缓存对象会随找size的限制会被purge，这样可以加入新的缓存对象。每次purge的时候都会调用注册的Listeners，如果抛出异常则这个缓存对象不会被删除。&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CachePolicyListener listener;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i=0; i&lt;listeners.size(); i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; listener = (CachePolicyListener)listeners.elementAt(i);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; listener.cacheObjectEvicted(entry.getValue());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
注意传入到cacheObjectEvicted中的变量是一个value，即处理的是缓存的对象而不是缓存项(CacheEntry)。 <br />
<br />
SoftCache利用了java的一个类SoftReference(详见内存优化的两个参数SoftReference和WeakReference)。它维护了两个map，一个是MRU对象_internal，另一个是Map对象_cacheMap，用于缓存SoftReference。<br />
<br />
put方法中有：_cacheMap.put(key, new Entry(key, value, _clearQueue));<br />
Entry类如下：<br />
<p>private static class Entry extends SoftReference {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private final Object _key;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Constructor that uses &lt;code&gt;value&lt;/code&gt; as the soft<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * reference's referent.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Entry(Object key, Object value, ReferenceQueue queue) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super(value, queue);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _key = key;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Gets the key<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * @return the key associated with this value.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; final Object getKey() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return _key;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Gets the value<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * @return the value; null if it is no longer accessible<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; final Object getValue() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return this.get();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }</p>
<br />
get方法：<br />
<br />
public Object get(Object key) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // first try the internal cache.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object value = _internal.get(key);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (value != null) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return value;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // poll and remove cleared references.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; removeClearedEntries();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Entry entry = (Entry)_cacheMap.get(key);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (entry == null) { // object is not in cache.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value = entry.getValue();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (value == null) { // object was in cache, but it was cleared.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // we have the object. so we try to re-insert it into internal cache<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _internal.put(key, value);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (CacheEvictionException e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // if the internal cache causes a fuss, we kick the object out.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _cacheMap.remove(key);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return value;<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
MRU的使用具体可以看CacheRecordManager类，它的创建在Provider类中：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RecordManager recman = new BaseRecordManager( name );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MRU cache = new MRU( cacheSize );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; recman = new CacheRecordManager( recman, cache );<br />
<br />
如果使用Factory获取RecordMagener<br />
RecordManagerFactory.createRecordManager( String name,&nbsp; Properties options )，<br />
得到的就是CacheRecordManager，如果非得使用BaseRecordManager：<br />
RecordManager recman = new BaseRecordManager( name );<br />
直接new一个即可。<br />
<br />
<br />
   <img src ="http://www.blogjava.net/persister/aggbug/268955.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-05-05 13:33 <a href="http://www.blogjava.net/persister/archive/2009/05/05/268955.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDBM学习一（简介）</title><link>http://www.blogjava.net/persister/archive/2009/05/04/268892.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Mon, 04 May 2009 14:16:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/05/04/268892.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/268892.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/05/04/268892.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/268892.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/268892.html</trackback:ping><description><![CDATA[<p>JDBM官方网站：<a href="http://jdbm.sourceforge.net/">http://jdbm.sourceforge.net/</a>&nbsp;or http://sourceforge.net/projects/jdbm/<br />
<strong><br />
JDBM is a transactional persistence engine for Java. It aims to be for Java what GDBM is for other languages (C/C++, Python, Perl, etc.): a fast, simple persistence engine. You can use it to store a mix of objects and BLOBs, and all updates are done in a transactionally safe manner. JDBM also provides scalable data structures, such as HTree and B+Tree, to support persistence of large object collections. </strong></p>
<br />
<p>ofbiz就是使用jdbm来进行缓存的，所以就花点时间来学习这个东西。<br />
看它代码量不是很大，决定对它的源码好好学习一下。<br />
下面是jdbm提供的一个example，先看看<br />
<br />
import jdbm.RecordManager;<br />
import jdbm.RecordManagerFactory;<br />
import jdbm.helper.FastIterator;<br />
import jdbm.htree.HTree;</p>
<p>import java.io.IOException;<br />
import java.util.Properties;</p>
<p>/**<br />
&nbsp;* Sample JDBM application to demonstrate the use of basic JDBM operations.<br />
&nbsp;*<br />
&nbsp;* @author &lt;a href="mailto:boisvert@intalio.com"&gt;Alex Boisvert&lt;/a&gt;<br />
&nbsp;* @version $Id: FruitBasket.java,v 1.3 2003/08/06 20:10:15 boisvert Exp $<br />
&nbsp;*/<br />
public class FruitBasket<br />
{<br />
&nbsp;&nbsp;&nbsp; RecordManager&nbsp; recman;<br />
&nbsp;&nbsp;&nbsp; HTree&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hashtable;<br />
&nbsp;&nbsp;&nbsp; FastIterator&nbsp;&nbsp; iter;<br />
&nbsp;&nbsp;&nbsp; String&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fruit;<br />
&nbsp;&nbsp;&nbsp; String&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; color;</p>
<p><br />
&nbsp;&nbsp;&nbsp; public FruitBasket()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws IOException<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // create or open fruits record manager<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Properties props = new Properties();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; recman = RecordManagerFactory.createRecordManager( "fruits", props );</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // create or load fruit basket (hashtable of fruits)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; long recid = recman.getNamedObject( "basket" );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( recid != 0 ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println( "Reloading existing fruit basket..." );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hashtable = HTree.load( recman, recid );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; showBasket();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println( "Creating new fruit basket..." );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hashtable = HTree.createInstance( recman );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; recman.setNamedObject( "basket", hashtable.getRecid() );&nbsp;//通过命名对象来实现id与名字的关联<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }</p>
<p><br />
&nbsp;&nbsp;&nbsp; public void runDemo()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws IOException<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // insert keys and values<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println( "Adding fruits to the basket..." );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hashtable.put( "bananas", "yellow" );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hashtable.put( "strawberries", "red" );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hashtable.put( "kiwis", "green" );</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; showBasket();</p>
<p><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // display color of a specific fruit<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println( "Get the color of bananas..." );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String bananasColor = (String) hashtable.get( "bananas" );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println( "bananas are " + bananasColor );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; recman.commit();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Thread.sleep( 10 * 1000 );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch ( Exception except ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // ignore<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // remove a specific fruit from hashtable<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print( "Removing bananas from the basket..." );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hashtable.remove( "bananas" );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; recman.commit();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println( " done." );</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // iterate over remaining objects<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println( "Remaining fruit colors:" );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; iter = hashtable.keys();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fruit = (String) iter.next();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while ( fruit != null ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; color = (String) hashtable.get( fruit );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println( fruit + " are " + color );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fruit = (String) iter.next();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // cleanup<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; recman.close();<br />
&nbsp;&nbsp;&nbsp; }</p>
<p><br />
&nbsp;&nbsp;&nbsp; public void showBasket() <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws IOException<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Display content of fruit basket<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print( "Fruit basket contains: " );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; iter = hashtable.keys();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fruit = (String) iter.next();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while ( fruit != null ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print( " " + fruit );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fruit = (String) iter.next();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println();<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; public static void main( String[] args )<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FruitBasket basket = new FruitBasket();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; basket.runDemo();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch ( IOException ioe ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ioe.printStackTrace();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>}<br />
</p>
<img src ="http://www.blogjava.net/persister/aggbug/268892.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-05-04 22:16 <a href="http://www.blogjava.net/persister/archive/2009/05/04/268892.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ThreadLocal的理解和使用</title><link>http://www.blogjava.net/persister/archive/2009/05/04/268889.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Mon, 04 May 2009 13:58:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/05/04/268889.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/268889.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/05/04/268889.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/268889.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/268889.html</trackback:ping><description><![CDATA[ThreadLocal的使用非常简单<br />
ThreadLocal user = new ThreadLoca();<br />
user.set("username", "jackliu");<br />
String username = user.get("username");<br />
<br />
ThreadLocal是维护线程本地变量的一个很好的方法<br />
只有本线程才能获得本线程内设置的变量，其他线程无法获取<br />
<br />
<p>&nbsp;/**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Returns the value in the current thread's copy of this thread-local<br />
&nbsp;&nbsp;&nbsp;&nbsp; * variable.&nbsp; Creates and initializes the copy if this is the first time<br />
&nbsp;&nbsp;&nbsp;&nbsp; * the thread has called this method.<br />
&nbsp;&nbsp;&nbsp;&nbsp; *<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @return the current thread's value of this thread-local<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public T get() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread t = Thread.currentThread();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ThreadLocalMap map = getMap(t);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (map != null)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (T)map.get(this);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Maps are constructed lazily.&nbsp; if the map for this thread<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // doesn't exist, create it, with this ThreadLocal and its<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // initial value as its only entry.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T value = initialValue(); //return null<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; createMap(t, value);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return value;<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Sets the current thread's copy of this thread-local variable<br />
&nbsp;&nbsp;&nbsp;&nbsp; * to the specified value.&nbsp; Many applications will have no need for<br />
&nbsp;&nbsp;&nbsp;&nbsp; * this functionality, relying solely on the {@link #initialValue}<br />
&nbsp;&nbsp;&nbsp;&nbsp; * method to set the values of thread-locals.<br />
&nbsp;&nbsp;&nbsp;&nbsp; *<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @param value the value to be stored in the current threads' copy of<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this thread-local.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public void set(T value) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread t = Thread.currentThread();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ThreadLocalMap map = getMap(t);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (map != null)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; map.set(this, value);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; createMap(t, value);<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Removes the value for this ThreadLocal.&nbsp; This may help reduce<br />
&nbsp;&nbsp;&nbsp;&nbsp; * the storage requirements of ThreadLocals.&nbsp; If this ThreadLocal<br />
&nbsp;&nbsp;&nbsp;&nbsp; * is accessed again, it will by default have its<br />
&nbsp;&nbsp;&nbsp;&nbsp; * &lt;tt&gt;initialValue&lt;/tt&gt;.<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @since 1.5<br />
&nbsp;&nbsp;&nbsp;&nbsp; **/</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; public void remove() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ThreadLocalMap m = getMap(Thread.currentThread());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (m != null)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m.remove(this);<br />
&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Get the map associated with a ThreadLocal. Overridden in<br />
&nbsp;&nbsp;&nbsp;&nbsp; * InheritableThreadLocal.<br />
&nbsp;&nbsp;&nbsp;&nbsp; *<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @param&nbsp; t the current thread<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @return the map<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; ThreadLocalMap getMap(Thread t) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return t.threadLocals;<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Create the map associated with a ThreadLocal. Overridden in<br />
&nbsp;&nbsp;&nbsp;&nbsp; * InheritableThreadLocal.<br />
&nbsp;&nbsp;&nbsp;&nbsp; *<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @param t the current thread<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @param firstValue value for the initial entry of the map<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @param map the map to store.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; void createMap(Thread t, T firstValue) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t.threadLocals = new ThreadLocalMap(this, firstValue);<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
前段时间有个需求就将是需要一个全局点去获取登陆用户的用户名。<br />
这个需求看起来很简单，但是却没有合适的办法。<br />
因为如果需要session变量，那么必须在servlet的处理类中，但是很多类并不是servlet<br />
而且也得不到request变量，所以在普通内里面没有办法获取到登陆用户名<br />
这个时候就需要使用到ThreadLocal类<br />
于是写了一个Filter。要注意的是因为web服务器针对每个web请求都会启动一个Thread<br />
所以，每次都需要调用UserUtil.setUserName方法才能保证每个线程都能得到正确的用户名。<br />
<br />
<br />
</p>
<p>import java.io.IOException;</p>
<p>import javax.servlet.Filter;<br />
import javax.servlet.FilterChain;<br />
import javax.servlet.FilterConfig;<br />
import javax.servlet.ServletException;<br />
import javax.servlet.ServletRequest;<br />
import javax.servlet.ServletResponse;<br />
import javax.servlet.http.HttpServletRequest;<br />
import javax.servlet.http.HttpSession;</p>
<p>import org.ofbiz.base.util.Debug;<br />
import org.ofbiz.entity.GenericValue;</p>
<p>import com.aicent.ccb.util.StringUtils;<br />
import com.aicent.ccb.util.UserUtil;</p>
<p>public class UserLogFilter implements Filter {<br />
&nbsp;public static final String module = UserLogFilter.class.getName();</p>
<p>&nbsp;public void destroy() {</p>
<p>&nbsp;}</p>
<p>&nbsp;public void doFilter(ServletRequest request, ServletResponse response,<br />
&nbsp;&nbsp;&nbsp;FilterChain chain) throws IOException, ServletException {</p>
<p>&nbsp;&nbsp;HttpServletRequest httpRequest = (HttpServletRequest) request;</p>
<p>&nbsp;&nbsp;String USERNAME = httpRequest.getParameter("USERNAME");</p>
<p>&nbsp;&nbsp;if (StringUtils.isValid(USERNAME)) {<br />
&nbsp;&nbsp;&nbsp;UserUtil.setUserName(USERNAME);<br />
&nbsp;&nbsp;&nbsp;Debug.logInfo("in request set user name=" + UserUtil.getUserName(),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;module);<br />
&nbsp;&nbsp;} else {<br />
&nbsp;&nbsp;&nbsp;HttpSession session = httpRequest.getSession();<br />
&nbsp;&nbsp;&nbsp;if (null != session) {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;GenericValue userLogin = (GenericValue) session<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.getAttribute("userLogin");<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (userLogin != null) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UserUtil.setUserName(userLogin.getString("userLoginId"));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Debug.logInfo(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"in session set user name=" + UserUtil.getUserName(),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;module);<br />
&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;} else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;Debug.logInfo("No user in the session", module);<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;chain.doFilter(request, response);<br />
&nbsp;}</p>
<p>&nbsp;public void init(FilterConfig fc) throws ServletException {</p>
<p>&nbsp;}</p>
<p>}<br />
<br />
<br />
public class UserUtil {<br />
&nbsp; private static final ThreadLocal user = new ThreadLocal() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Object initialValue() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return "Unknown User";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp; };<br />
&nbsp; public static void setUserName(String userName){<br />
&nbsp;&nbsp; user.set(userName);<br />
&nbsp; }<br />
&nbsp; <br />
&nbsp; public static String getUserName(){<br />
&nbsp;&nbsp; return (String)user.get();<br />
&nbsp; }<br />
}<br />
</p>
<img src ="http://www.blogjava.net/persister/aggbug/268889.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-05-04 21:58 <a href="http://www.blogjava.net/persister/archive/2009/05/04/268889.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>交易中间件与xa规范</title><link>http://www.blogjava.net/persister/archive/2009/04/18/266242.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Fri, 17 Apr 2009 16:05:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/04/18/266242.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/266242.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/04/18/266242.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/266242.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/266242.html</trackback:ping><description><![CDATA[<span style="font-size: 14pt;">
<font size="2">xa是x／open dtp定义的交易中间件与数据库之间的接口规范（即接口函数），交易中间件用它来通知数据库事务的开始、结束以及提交、回滚等。xa接口函数则由数据库厂商提供。<br />
</font><br />
<font size="2">　　在谈到xa规范之前，必须首先了解分布式事务处理（distributed transaction processing）的概念。transaction，即事务，指一个程序或程序段，在一个或多个资源如数据库或文件上为完成某些功能的执行过程的集合。<br />
<br />
分布式事务处理是指一个事务可能涉及多个数据库操作，分布式事务处理的关键是必须有一种方法可以管理事务在任何地方所做的所有动作，提交或回滚事务的决定必须产生统一的结果（全部提交或全部回滚）。<br />
<br />
x／open组织（即现在的open group）定义了分布式事务处理模型。x／open dtp模型（1994）包括应用程序（ap）、事务管理器（tm）、资源管理器（rm）、通信资源管理器（crm）四部分。一般，常见的事务管理器（tm）是交易中间件，常见的资源管理器（rm）是数据库，常见的通信资源管理器（crm）是消息中间件。为表述方便起见，在本文中直接以其常见表现形式进行描述。<br />
<br />
通常把一个数据库内部的事务处理，如对多个表的操作，作为本地事务看待。数据库的事务处理对象是本地事务，而分布式事务处理的对象是全局事务。<br />
<br />
所谓全局事务，是指分布式事务处理环境中，多个数据库可能需要共同完成一个工作，这个工作即是一个全局事务，例如，一个事务中可能更新几个不同的数据库。对数据库的操作发生在系统的各处但必须全部被提交或回滚。此时一个数据库对自己内部所做操作的提交不仅依赖本身操作是否成功，还要依赖与全局事务相关的其它数据库的操作是否成功，如果任一数据库的任一操作失败，则参与此事务的所有数据库所做的所有操作都必须回滚。<br />
<br />
一般情况下，某一数据库无法知道其它数据库在做什么，因此，在一个dtp环境中，交易中间件是必需的，由它通知和协调相关数据库的提交或回滚。而一个数据库只将其自己所做的操作（可恢复）影射到全局事务中。</font><strong><font size="2"><br />
</font></strong><br />
<font size="2">xa规范的基础是两阶段提交协议。<br />
<br />
在第一阶段，交易中间件请求所有相关数据库准备提交（预提交）各自的事务分支，以确认是否所有相关数据库都可以提交各自的事务分支。当某一数据库收到预提交后，如果可以提交属于自己的事务分支，则将自己在该事务分支中所做的操作固定记录下来，并给交易中间件一个同意提交的应答，此时数据库将不能再在该事务分支中加入任何操作，但此时数据库并没有真正提交该事务，数据库对共享资源的操作还未释放（处于上锁状态）。如果由于某种原因数据库无法提交属于自己的事务分支，它将回滚自己的所有操作，释放对共享资源上的锁，并返回给交易中间件失败应答。<br />
<br />
在第二阶段，交易中间件审查所有数据库返回的预提交结果，如所有数据库都可以提交，交易中间件将要求所有数据库做正式提交，这样该全局事务被提交。而如果有任一数据库预提交返回失败，交易中间件将要求所有其它数据库回滚其操作，这样该全局事务被回滚。<br />
<br />
以一个全局事务为例，ap首先通知交易中间件开始一个全局事务，交易中间件通过xa接口函数通知数据库开始事务，然后ap可以对数据库管理的资源进行操作，数据库系统记录事务对本地资源的所有操作。操作完成后交易中间件通过xa接口函数通知数据库操作完成。交易中间件负责记录ap操作过哪些数据库（事务分支）。ap根据情况通知交易中间件提交该全局事务，交易中间件会通过xa接口函数要求各个数据库做预提交，所有数据库返回成功后要求各个数据库做正式提交，此时一笔全局事务结束。<br />
<br />
xa规范对应用来说，最大好处在于事务的完整性由交易中间件和数据库通过xa接口控制，ap只需要关注与数据库的应用逻辑的处理，而无需过多关心事务的完整性，应用设计开发会简化很多。<br />
<br />
具体来说，如果没有交易中间件，应用系统需要在程序内部直接通知数据库开始、结束和提交事务，当出现异常情况时必须由专门的程序对数据库进行反向操作才能完成回滚。如果是有很多事务分支的全局事务，回滚时情况将变得异常复杂。而使用xa接口，则全局事务的提交是由交易中间件控制，应用程序只需通知交易中间件提交或回滚事务，就可以控制整个事务（可能涉及多个异地的数据库）的全部提交或回滚，应用程序完全不用考虑冲正逻辑。<br />
<span style="font-size: 12pt;"><font size="2"><span style="font-size: 10pt;"><font size="2"><span style="font-size: 12pt;"><font size="2"><span style="font-size: 10pt;"><span style="font-size: 8pt;"><font size="2"><span style="font-size: 10pt;"><font size="2"><br />
</font><a href="http://www.ibm.com/developerworks/cn/data/library/techarticles/dm-0505weber/index.html">http://www.ibm.com/developerworks/cn/data/library/techarticles/dm-0505weber/index.html</a><br />
这篇文章里面有非常详细的代码描绘，值得参考。<br />
<span style="font-size: 10pt;"><span style="font-size: 14pt;"><font size="2"><span style="font-size: 12pt;"><font size="2"><span style="font-size: 10pt;"><font size="2"><span style="font-size: 12pt;"><font size="2"><span style="font-size: 10pt;"><span style="font-size: 8pt;"><font size="2"><span style="font-size: 10pt;"><br />
</span></font></span></span></font></span></font></span></font></span></font></span><a href="http://www.cnblogs.com/sunwei2012/archive/2010/01/08/1642295.html">http://www.cnblogs.com/sunwei2012/archive/2010/01/08/1642295.html</a><br />
这也是一篇不错的文章。<br />
</span></span></font></span></span></font></span></font></span></font></span></font></span><br />
<span style="font-size: 14pt;"><font size="2"><span style="font-size: 12pt;"><font size="2"><span style="font-size: 10pt;"><font size="2"><span style="font-size: 12pt;"><font size="2"><span style="font-size: 10pt;"><span style="font-size: 8pt;"><font size="2"></font></span></span></font></span></font>
</span></font></span></font><br />
</span>
<img src ="http://www.blogjava.net/persister/aggbug/266242.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-04-18 00:05 <a href="http://www.blogjava.net/persister/archive/2009/04/18/266242.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>泛型</title><link>http://www.blogjava.net/persister/archive/2009/04/14/265563.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Tue, 14 Apr 2009 09:10:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/04/14/265563.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/265563.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/04/14/265563.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/265563.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/265563.html</trackback:ping><description><![CDATA[1，泛型中的&#8216;万用字符&#8217;：<br />
<br />
&lt;T extends&nbsp; Comparable&gt; ：表示T是实现了Comparable的类型（在&#8216;泛型&#8217;中extends表示extends或者implement）<br />
<br />
&lt;? extends T&gt; ：表示必须是T或者T的子类<br />
<br />
ArrayList&lt;? extends Animal&gt; ：以实现或继承Animal的类型为元素类型的ArrayList<br />
<br />
2，相同功能的另一种语法：<br />
<br />
public &lt;T extends Animal&gt; void takeThing(ArrayList&lt;T&gt; list);<br />
<br />
等同于：public void takeThing(ArrayList&lt;? extends Animal&gt; list); <br />
<br />
<br />
更详细请参考：<br />
<br />
<a href="http://baike.baidu.com/view/1436058.htm">http://baike.baidu.com/view/1436058.htm</a>&nbsp; java泛型
<img src ="http://www.blogjava.net/persister/aggbug/265563.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-04-14 17:10 <a href="http://www.blogjava.net/persister/archive/2009/04/14/265563.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关闭钩子(shutdown hook)的作用</title><link>http://www.blogjava.net/persister/archive/2009/03/05/258094.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Thu, 05 Mar 2009 15:13:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/03/05/258094.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/258094.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/03/05/258094.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/258094.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/258094.html</trackback:ping><description><![CDATA[<div id="memo">
<p>JDK1.3介绍了java.lang.Runtime class的addShutdownHook()方法。如果你需要在你的程序关闭前采取什么措施，那么关闭钩子（<strong>shutdown</strong> <strong>hook</strong>）是很有用的。</p>
<p>&nbsp; <br />
要加关闭钩子（<strong>shutdown</strong> <strong>hook</strong>），需要先创建一个java.lang.Thread 类的实例，把它作为addShutdownHook()方法的参数。因为关闭钩子（<strong>shutdown</strong> <strong>hook</strong>）简短而扼要的，所以用匿名嵌套类很适合。</p>
<p>下面是简单的关闭钩子，它打印出"shutting down"：</p>
<p>Runtime.getRuntime().addShutdownHook(new Thread() {<br />
&nbsp;&nbsp;&nbsp; public void run() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("shutting down");<br />
&nbsp;&nbsp;&nbsp; }<br />
}); </p>
<p>虚拟机关闭时，它会调用线程的start()函数。</p>
<p>除了加关闭钩子（<strong>shutdown</strong> <strong>hook</strong>）外，你也可以通过对前一个注册线程的引用，调用方法注销钩子。记住：为了注销钩子，你必须有它的引用，这样匿名类在注销后才不会发生作用。</p>
<p>如果在你的程序关闭时，你需要做一些工作，清除工作，释放资源等等，那么你会发现关闭钩子（<strong>shutdown</strong> <strong>hook</strong>）很有用。<!--新闻内容//--><!--评论发布--></p>
</div>
<img src ="http://www.blogjava.net/persister/aggbug/258094.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-03-05 23:13 <a href="http://www.blogjava.net/persister/archive/2009/03/05/258094.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> 判断两个路径是否指向同一个文件</title><link>http://www.blogjava.net/persister/archive/2009/03/05/258075.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Thu, 05 Mar 2009 13:48:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/03/05/258075.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/258075.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/03/05/258075.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/258075.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/258075.html</trackback:ping><description><![CDATA[我们知道在Windows操作系统下文件名是不区分大小写；<br />
<br />
另外在不同的操作系统下可以用 . 来表示当前目录，或者直接只写文件名也表示默认为当前目录，<br />
<br />
例如当前目录是D:\work，那么文件D:\work\aaa.txt和.\Aaa.txt 实际上指的是磁盘上的同一个文件，<br />
<br />
但是程序怎么来判断这种情况呢？请看下面代码 <br />
<br />
/** * 判断两个File对象是否指向同一个文件 <br />
<br />
* @throws IOException */ <br />
<br />
protected static void testCanonicalFile() throws IOException<br />
<br />
{&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File f1 = new File("D:\work\AAA.txt");&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File f2 = new File("./aaa.txt");&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;boolean sameFile = f1.getCanonicalFile(). equals(f2.getCanonicalFile());&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(sameFile); <br />
<br />
} <br />
<br />
通过getCanonicalFile方法来获取某个文件在当前操作系统下对应的目标文件，<br />
<br />
只要两个路径指向同一个文件，<br />
<br />
则两个文件对象的getCanonicalFile返回的对象一定相等，<br />
<br />
因此上面的例子打印的值是 true.
<img src ="http://www.blogjava.net/persister/aggbug/258075.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-03-05 21:48 <a href="http://www.blogjava.net/persister/archive/2009/03/05/258075.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java性能测试工具JProfiler试用</title><link>http://www.blogjava.net/persister/archive/2008/12/26/248370.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Fri, 26 Dec 2008 01:37:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2008/12/26/248370.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/248370.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2008/12/26/248370.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/248370.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/248370.html</trackback:ping><description><![CDATA[<meta content="Word.Document" name="ProgId" />
<meta content="Microsoft Word 11" name="Generator" />
<meta content="Microsoft Word 11" name="Originator" />
<link href="file:///C:%5CDOCUME%7E1%5Clby%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml" rel="File-List" />
<link href="file:///C:%5CDOCUME%7E1%5Clby%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_editdata.mso" rel="Edit-Time-Data" /><!--[if !mso]>
<style>
v\:* {behavior:url(#default#VML);}
o\:* {behavior:url(#default#VML);}
w\:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
</style>
<![endif]--><!--[if gte mso 9]><xml>
<w:WordDocument>
<w:View>Normal</w:View>
<w:Zoom>0</w:Zoom>
<w:PunctuationKerning/>
<w:DrawingGridVerticalSpacing>7.8 磅</w:DrawingGridVerticalSpacing>
<w:DisplayHorizontalDrawingGridEvery>0</w:DisplayHorizontalDrawingGridEvery>
<w:DisplayVerticalDrawingGridEvery>2</w:DisplayVerticalDrawingGridEvery>
<w:ValidateAgainstSchemas/>
<w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>
<w:IgnoreMixedContent>false</w:IgnoreMixedContent>
<w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>
<w:Compatibility>
<w:SpaceForUL/>
<w:BalanceSingleByteDoubleByteWidth/>
<w:DoNotLeaveBackslashAlone/>
<w:ULTrailSpace/>
<w:DoNotExpandShiftReturn/>
<w:AdjustLineHeightInTable/>
<w:BreakWrappedTables/>
<w:SnapToGridInCell/>
<w:WrapTextWithPunct/>
<w:UseAsianBreakRules/>
<w:DontGrowAutofit/>
<w:UseFELayout/>
</w:Compatibility>
<w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel>
</w:WordDocument>
</xml><![endif]--><!--[if gte mso 9]><xml>
<w:LatentStyles deflockedstate="false" latentstylecount="156">
</w:LatentStyles>
</xml><![endif]-->
<style>
<!-- /* Font Definitions */
@font-face
{font-family:宋体;
panose-1:2 1 6 0 3 1 1 1 1 1;
mso-font-alt:SimSun;
mso-font-charset:134;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:3 135135232 16 0 262145 0;}
@font-face
{font-family:"\@宋体";
panose-1:2 1 6 0 3 1 1 1 1 1;
mso-font-charset:134;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:3 135135232 16 0 262145 0;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{mso-style-parent:"";
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
text-justify:inter-ideograph;
mso-pagination:none;
font-size:10.5pt;
mso-bidi-font-size:12.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:宋体;
mso-font-kerning:1.0pt;}
a:link, span.MsoHyperlink
{color:blue;
text-decoration:underline;
text-underline:single;}
a:visited, span.MsoHyperlinkFollowed
{color:purple;
text-decoration:underline;
text-underline:single;}
/* Page Definitions */
@page
{mso-page-border-surround-header:no;
mso-page-border-surround-footer:no;}
@page Section1
{size:595.3pt 841.9pt;
margin:72.0pt 90.0pt 72.0pt 90.0pt;
mso-header-margin:42.55pt;
mso-footer-margin:49.6pt;
mso-paper-source:0;
layout-grid:15.6pt;}
div.Section1
{page:Section1;}
/* List Definitions */
@list l0
{mso-list-id:407458586;
mso-list-template-ids:-1651201720;}
@list l0:level1
{mso-level-number-format:bullet;
mso-level-text:;
mso-level-tab-stop:36.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l1
{mso-list-id:868488523;
mso-list-template-ids:353254270;}
@list l1:level1
{mso-level-number-format:bullet;
mso-level-text:;
mso-level-tab-stop:36.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l2
{mso-list-id:940337852;
mso-list-template-ids:226030120;}
@list l2:level1
{mso-level-number-format:bullet;
mso-level-text:;
mso-level-tab-stop:36.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l3
{mso-list-id:1568027262;
mso-list-template-ids:1928918176;}
@list l3:level1
{mso-level-number-format:bullet;
mso-level-text:;
mso-level-tab-stop:36.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l4
{mso-list-id:1873835036;
mso-list-template-ids:259129438;}
@list l4:level1
{mso-level-number-format:bullet;
mso-level-text:;
mso-level-tab-stop:36.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l4:level2
{mso-level-start-at:3;
mso-level-number-format:japanese-counting;
mso-level-text:%2、;
mso-level-tab-stop:78.0pt;
mso-level-number-position:left;
margin-left:78.0pt;
text-indent:-24.0pt;}
ol
{margin-bottom:0cm;}
ul
{margin-bottom:0cm;}
-->
</style>
<!--[if gte mso 10]>
<style>
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:普通表格;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-parent:"";
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin:0cm;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:10.0pt;
font-family:"Times New Roman";
mso-ansi-language:#0400;
mso-fareast-language:#0400;
mso-bidi-language:#0400;}
</style>
<![endif]-->
<p class="MsoNormal"><span style="font-size: 12pt;" lang="EN-US">JProfiler</span><span style="font-size: 12pt; font-family: 宋体;">测试</span><span style="font-size: 12pt;" lang="EN-US">RCP</span><span style="font-size: 12pt; font-family: 宋体;">教程</span><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 6pt;"><span style="font-size: 12pt; font-family: 宋体;">一、下载、注册：</span><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 6pt;"><span style="font-size: 12pt;" lang="EN-US">1</span><span style="font-size: 12pt; font-family: 宋体;">、下载：我们可以从</span><span style="font-size: 12pt;" lang="EN-US">JProfiler</span><span style="font-size: 12pt; font-family: 宋体;">的官方网站下载到最新版本的</span><span style="font-size: 12pt;" lang="EN-US">JProfiler</span><span style="font-size: 12pt; font-family: 宋体;">，我用的是目前最新版</span><span style="font-size: 12pt;" lang="EN-US">JProfiler6</span><span style="font-size: 12pt; font-family: 宋体;">。</span><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 6pt;"><span style="font-size: 12pt; font-family: 宋体;">下载地址：</span><span style="font-size: 12pt;" lang="EN-US"><a href="http://www.ej-technologies.com/products/jprofiler/overview.html">http://www.ej-technologies.com/products/jprofiler/overview.html</a><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 6pt;"><span style="font-size: 12pt;" lang="EN-US">2</span><span style="font-size: 12pt; font-family: 宋体;">、注册：在官方网站上当我们确定了下载的版本后会出现如下界面：</span></p>
<p class="MsoNormal" style="margin-left: 6pt;">
<meta content="Word.Document" name="ProgId" />
<meta content="Microsoft Word 11" name="Generator" />
<meta content="Microsoft Word 11" name="Originator" />
<link href="file:///C:%5CDOCUME%7E1%5Clby%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml" rel="File-List" />
<link href="file:///C:%5CDOCUME%7E1%5Clby%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_editdata.mso" rel="Edit-Time-Data" /><!--[if !mso]>
<style>
v\:* {behavior:url(#default#VML);}
o\:* {behavior:url(#default#VML);}
w\:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
</style>
<![endif]--><!--[if gte mso 9]><xml>
<w:WordDocument>
<w:View>Normal</w:View>
<w:Zoom>0</w:Zoom>
<w:PunctuationKerning/>
<w:DrawingGridVerticalSpacing>7.8 磅</w:DrawingGridVerticalSpacing>
<w:DisplayHorizontalDrawingGridEvery>0</w:DisplayHorizontalDrawingGridEvery>
<w:DisplayVerticalDrawingGridEvery>2</w:DisplayVerticalDrawingGridEvery>
<w:ValidateAgainstSchemas/>
<w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>
<w:IgnoreMixedContent>false</w:IgnoreMixedContent>
<w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>
<w:Compatibility>
<w:SpaceForUL/>
<w:BalanceSingleByteDoubleByteWidth/>
<w:DoNotLeaveBackslashAlone/>
<w:ULTrailSpace/>
<w:DoNotExpandShiftReturn/>
<w:AdjustLineHeightInTable/>
<w:BreakWrappedTables/>
<w:SnapToGridInCell/>
<w:WrapTextWithPunct/>
<w:UseAsianBreakRules/>
<w:DontGrowAutofit/>
<w:UseFELayout/>
</w:Compatibility>
<w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel>
</w:WordDocument>
</xml><![endif]--><!--[if gte mso 9]><xml>
<w:LatentStyles deflockedstate="false" latentstylecount="156">
</w:LatentStyles>
</xml><![endif]-->
<style>
<!-- /* Font Definitions */
@font-face
{font-family:宋体;
panose-1:2 1 6 0 3 1 1 1 1 1;
mso-font-alt:SimSun;
mso-font-charset:134;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:3 135135232 16 0 262145 0;}
@font-face
{font-family:"\@宋体";
panose-1:2 1 6 0 3 1 1 1 1 1;
mso-font-charset:134;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:3 135135232 16 0 262145 0;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{mso-style-parent:"";
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
text-justify:inter-ideograph;
mso-pagination:none;
font-size:10.5pt;
mso-bidi-font-size:12.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:宋体;
mso-font-kerning:1.0pt;}
/* Page Definitions */
@page
{mso-page-border-surround-header:no;
mso-page-border-surround-footer:no;}
@page Section1
{size:612.0pt 792.0pt;
margin:72.0pt 90.0pt 72.0pt 90.0pt;
mso-header-margin:36.0pt;
mso-footer-margin:36.0pt;
mso-paper-source:0;}
div.Section1
{page:Section1;}
-->
</style>
<!--[if gte mso 10]>
<style>
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:普通表格;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-parent:"";
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin:0cm;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:10.0pt;
font-family:"Times New Roman";
mso-ansi-language:#0400;
mso-fareast-language:#0400;
mso-bidi-language:#0400;}
</style>
<![endif]--><span style="font-size: 12pt; font-family: 宋体;">我们添写对应的信息后，网站会将注册码发送到你所添写的邮箱当中，打开邮箱便可获得一个免费使用</span><span style="font-size: 12pt;" lang="EN-US">10</span><span style="font-size: 12pt; font-family: 宋体;">天的</span><span style="font-size: 12pt;" lang="EN-US">Key</span><span style="font-size: 12pt; font-family: 宋体;">码，</span><span style="font-size: 12pt;" lang="EN-US">10</span><span style="font-size: 12pt; font-family: 宋体;">天后</span><span style="font-size: 12pt;" lang="EN-US">Key</span><span style="font-size: 12pt; font-family: 宋体;">码便不可用，我们得重复上述方法重新申请</span><span style="font-size: 12pt;" lang="EN-US">Key</span><span style="font-size: 12pt; font-family: 宋体;">码。</span><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 6pt;"><span style="font-size: 12pt;" lang="EN-US"><o:p>&nbsp;</o:p></span><span style="font-size: 12pt; font-family: 宋体;">、</span><span style="font-size: 12pt;" lang="EN-US">JProfiler</span><span style="font-size: 12pt; font-family: 宋体;">主要功能简介：</span><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: Arial;" lang="EN-US">1</span><span style="font-size: 12pt; font-family: 宋体;">．</span><span style="font-size: 12pt; font-family: 宋体;">内存剖析 </span><span style="font-size: 12pt; font-family: Arial;" lang="EN-US">Memory profiler</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"> </span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-indent: 21pt; text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">JProfiler </span><span style="font-size: 12pt; font-family: 宋体;">的内存视图部分可以提供动态的内存使用状况更新视图和显示关于内存分配状况信息的视图。所有的视图都有几个聚集层并且能够显示现有存在的对象和作为垃圾回收的对象。 </span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<ul style="margin-top: 0cm;" type="disc">
    <li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">所有对象 </span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><br />
    </span><span style="font-size: 12pt; font-family: 宋体;">显示类或在状况统计和尺码信息堆上所有对象的包。你可以标记当前值并显示差异值。 <span lang="EN-US"><o:p></o:p></span></span>
    </li>
    <li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">记录对象<span lang="EN-US"> Record objects </span></span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><br />
    </span><span style="font-size: 12pt; font-family: 宋体;">显示类或所有已记录对象的包。你可以标记出当前值并且显示差异值。 <span lang="EN-US"><o:p></o:p></span></span>
    </li>
    <li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">分配访问树<span lang="EN-US"> Allocation call tree </span></span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><br />
    </span><span style="font-size: 12pt; font-family: 宋体;">显示一棵请求树或者方法、类、包或对已选择类有带注释的分配信息的<span lang="EN-US">J2EE</span>组件。 <span lang="EN-US"><o:p></o:p></span></span>
    </li>
    <li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">分配热点<span lang="EN-US"> Allocation hot spots </span></span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><br />
    </span><span style="font-size: 12pt; font-family: 宋体;">显示一个列表，包括方法、类、包或分配已选类的<span lang="EN-US">J2EE</span>组件。你可以标注当前值并且显示差异值。对于每个热点都可以显示它的跟踪记录树。 <span lang="EN-US"><o:p></o:p></span></span></li>
</ul>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: Arial;" lang="EN-US">2</span><span style="font-size: 12pt; font-family: 宋体;">．</span><span style="font-size: 12pt; font-family: 宋体;">堆遍历 </span><span style="font-size: 12pt; font-family: Arial;" lang="EN-US">Heap walker</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"> </span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-indent: 21pt; text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">在<span lang="EN-US">JProfiler</span>的堆遍历器<span lang="EN-US">(Heap walker)</span>中，你可以对堆的状况进行快照并且可以通过选择步骤下寻找感兴趣的对象。堆遍历器有五个视图： <span lang="EN-US"><o:p></o:p></span></span></p>
<ul style="margin-top: 0cm;" type="disc">
    <li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">类<span lang="EN-US"> Classes </span></span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><br />
    </span><span style="font-size: 12pt; font-family: 宋体;">显示所有类和它们的实例。 <span lang="EN-US"><o:p></o:p></span></span>
    </li>
    <li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">分配<span lang="EN-US"> Allocations </span></span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><br />
    </span><span style="font-size: 12pt; font-family: 宋体;">为所有记录对象显示分配树和分配热点。 <span lang="EN-US"><o:p></o:p></span></span>
    </li>
    <li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">索引<span lang="EN-US"> References </span></span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><br />
    </span><span style="font-size: 12pt; font-family: 宋体;">为单个对象和&#8220;显示到垃圾回收根目录的路径&#8221;提供索引图的显示功能。还能提供合并输入视图和输出视图的功能。 <span lang="EN-US"><o:p></o:p></span></span>
    </li>
    <li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">数据<span lang="EN-US"> Data </span></span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><br />
    </span><span style="font-size: 12pt; font-family: 宋体;">为单个对象显示实例和类数据。 <span lang="EN-US"><o:p></o:p></span></span>
    </li>
    <li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">时间<span lang="EN-US"> Time </span></span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><br />
    </span><span style="font-size: 12pt; font-family: 宋体;">显示一个对已记录对象的解决时间的柱状图。 <span lang="EN-US"><o:p></o:p></span></span></li>
</ul>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: Arial;" lang="EN-US">3</span><span style="font-size: 12pt; font-family: 宋体;">．</span><span style="font-size: 12pt; font-family: Arial;" lang="EN-US">CPU</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"> </span><span style="font-size: 12pt; font-family: 宋体;">剖析 </span><span style="font-size: 12pt; font-family: Arial;" lang="EN-US">CPU Views</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"> </span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-indent: 21pt; text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">JProfiler </span><span style="font-size: 12pt; font-family: 宋体;">提供不同的方法来记录访问树以优化性能和细节。线程或者线程组以及线程状况可以被所有的视图选择。所有的视图都可以聚集到方法、类、包或<span lang="EN-US">J2EE</span>组件等不同层上。<span lang="EN-US">CPU</span>视图部分包括： </span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<ul style="margin-top: 0cm;" type="disc">
    <li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">访问树<span lang="EN-US"> Call tree </span></span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><br />
    </span><span style="font-size: 12pt; font-family: 宋体;">显示一个积累的自顶向下的树<span lang="EN-US">,</span>树中包含所有在<span lang="EN-US">JVM</span>中已记录的访问队列。<span lang="EN-US">JDBC,JMS</span>和<span lang="EN-US">JNDI</span>服务请求都被注释在请求树中。请求树可以根据<span lang="EN-US">Servlet</span>和<span lang="EN-US">JSP</span>对<span lang="EN-US">URL</span>的不同需要进行拆分。 <span lang="EN-US"><o:p></o:p></span></span>
    </li>
    <li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">热点<span lang="EN-US"> Hot spots </span></span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><br />
    </span><span style="font-size: 12pt; font-family: 宋体;">显示消耗时间最多的方法的列表。对每个热点都能够显示回溯树。该热点可以按照方法请求，<span lang="EN-US">JDBC</span>，<span lang="EN-US">JMS</span>和<span lang="EN-US">JNDI</span>服务请求以及按照<span lang="EN-US">URL</span>请求来进行计算。 <span lang="EN-US"><o:p></o:p></span></span>
    </li>
    <li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">访问图<span lang="EN-US"> Call graph </span></span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><br />
    </span><span style="font-size: 12pt; font-family: 宋体;">显示一个从已选方法、类、包或<span lang="EN-US">J2EE</span>组件开始的访问队列的图。 <span lang="EN-US"><o:p></o:p></span></span></li>
</ul>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: Arial;" lang="EN-US">4</span><span style="font-size: 12pt; font-family: 宋体;">．</span><span style="font-size: 12pt; font-family: 宋体;">线程剖析 </span><span style="font-size: 12pt; font-family: Arial;" lang="EN-US">Thread profiler</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"> </span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-indent: 21pt; text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">对线程剖析，<span lang="EN-US">JProfiler</span>提供以下视图<span lang="EN-US">: <o:p></o:p></span></span></p>
<ul style="margin-top: 0cm;" type="disc">
    <li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">线程历史<span lang="EN-US"> Thread history </span></span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><br />
    </span><span style="font-size: 12pt; font-family: 宋体;">显示一个与线程活动和线程状态在一起的活动时间表。 <span lang="EN-US"><o:p></o:p></span></span>
    </li>
    <li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">线程监控<span lang="EN-US"> Thread monitor </span></span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><br />
    </span><span style="font-size: 12pt; font-family: 宋体;">显示一个列表，包括所有的活动线程以及它们目前的活动状况。 <span lang="EN-US"><o:p></o:p></span></span>
    </li>
    <li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">死锁探测图表<span lang="EN-US"> Deadlock Detection </span></span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><br />
    </span><span style="font-size: 12pt; font-family: 宋体;">显示一个包含了所有在<span lang="EN-US">JVM</span>里的死锁图表。 <span lang="EN-US"><o:p></o:p></span></span>
    </li>
    <li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">目前使用的监测器<span lang="EN-US"> Current monitor useage </span></span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><br />
    </span><span style="font-size: 12pt; font-family: 宋体;">显示目前使用的监测器并且包括它们的关联线程。 <span lang="EN-US"><o:p></o:p></span></span>
    </li>
    <li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">历史检测记录<span lang="EN-US"> History usage history </span></span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><br />
    </span><span style="font-size: 12pt; font-family: 宋体;">显示重大的等待事件和阻塞事件的历史记录。 <span lang="EN-US"><o:p></o:p></span></span>
    </li>
    <li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">监测使用状态<span lang="EN-US"> Monitor usage statistics </span></span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><br />
    </span><span style="font-size: 12pt; font-family: 宋体;">显示分组监测，线程和监测类的统计监测数据。 <span lang="EN-US"><o:p></o:p></span></span></li>
</ul>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: Arial;" lang="EN-US">5</span><span style="font-size: 12pt; font-family: 宋体;">．</span><span style="font-size: 12pt; font-family: Arial;" lang="EN-US">VM </span><span style="font-size: 12pt; font-family: 宋体;">遥感勘测技术 </span><span style="font-size: 12pt; font-family: Arial;" lang="EN-US">VM telemetry</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"> </span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-indent: 21pt; text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">观察<span lang="EN-US">JVM</span>的内部状态，<span lang="EN-US">JProfiler</span>提供了不同的遥感勘测视图，如下所示<span lang="EN-US">: <o:p></o:p></span></span></p>
<ul style="margin-top: 0cm;" type="disc">
    <li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">堆<span lang="EN-US"> Heap </span></span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><br />
    </span><span style="font-size: 12pt; font-family: 宋体;">显示一个堆的使用状况和堆尺寸大小活动时间表。 <span lang="EN-US"><o:p></o:p></span></span>
    </li>
    <li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">记录的对象<span lang="EN-US"> Recorded objects </span></span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><br />
    </span><span style="font-size: 12pt; font-family: 宋体;">显示一张关于活动对象与数组的图表的活动时间表。 <span lang="EN-US"><o:p></o:p></span></span>
    </li>
    <li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">垃圾回收<span lang="EN-US"> Garbage collector </span></span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><br />
    </span><span style="font-size: 12pt; font-family: 宋体;">显示一张关于垃圾回收活动的活动时间表。 <span lang="EN-US"><o:p></o:p></span></span>
    </li>
    <li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">类<span lang="EN-US"> Classes </span></span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><br />
    </span><span style="font-size: 12pt; font-family: 宋体;">显示一个与已装载类的图表的活动时间表。 <span lang="EN-US"><o:p></o:p></span></span></li>
</ul>
<p class="MsoNormal" style="margin-left: 6pt;"><span style="font-size: 12pt; font-family: 宋体;">线程<span lang="EN-US"> Threads </span></span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><br />
</span><span style="font-size: 12pt; font-family: 宋体;">显示一个与动态线程图表的活动时间表</span><span style="font-size: 12pt; font-family: 宋体;">。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="margin-left: 6pt;"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p>&nbsp;</o:p></span><span style="font-size: 12pt; font-family: 宋体;">三、<span lang="EN-US">JProfiler</span>如何测试<span lang="EN-US">RCP</span>程序<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="margin-left: 6pt;"><strong><span style="font-size: 12pt;" lang="EN-US">1</span></strong><strong><span style="font-size: 12pt; font-family: 宋体;">、启动</span></strong><strong><span style="font-size: 12pt;" lang="EN-US">JProfiler5.1.4</span></strong><strong><span style="font-size: 12pt; font-family: 宋体;">后会出现&#8220;</span></strong><strong><span style="font-size: 12pt;" lang="EN-US">Quick Start</span></strong><strong><span style="font-size: 12pt; font-family: 宋体;">&#8221;窗口，如图：</span></strong><strong><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></strong></p>
<p class="MsoNormal" style="margin-left: 6pt;"><span style="font-size: 12pt; font-family: 宋体;">在这里我们要选择要测试程序的类型，我们选择第二项，单击&#8220;</span><span style="font-size: 12pt;" lang="EN-US">Next</span><span style="font-size: 12pt; font-family: 宋体;">&#8221;，进入&#8220;</span><span style="font-size: 12pt;" lang="EN-US">Session Settings</span><span style="font-size: 12pt; font-family: 宋体;">&#8221;配置窗口。</span><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 6pt;"><strong><span style="font-size: 12pt;" lang="EN-US">2</span></strong><strong><span style="font-size: 12pt; font-family: 宋体;">、</span></strong><strong><span style="font-size: 12pt;" lang="EN-US">Session Settings</span></strong><strong><span style="font-size: 12pt; font-family: 宋体;">的窗口的配置</span></strong><strong><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></strong></p>
<p class="MsoNormal" style="margin-left: 6pt;"><span style="font-size: 12pt; font-family: 宋体;">运行界面如图：</span><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 6pt;"><span style="font-size: 12pt; font-family: 宋体;">此窗口共有四个选项卡，通常情况下我们只需添写&#8220;</span><span style="font-size: 12pt;" lang="EN-US">Application Settings</span><span style="font-size: 12pt; font-family: 宋体;">&#8221;中的相关信息，其中：</span><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 6pt;"><strong><span style="font-size: 12pt;" lang="EN-US">Session name</span></strong><span style="font-size: 12pt; font-family: 宋体;">：此次测试的名字，可任意添写。</span><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 78.3pt; text-indent: -72.3pt;"><strong><span style="font-size: 12pt;" lang="EN-US">Session Type</span></strong><span style="font-size: 12pt; font-family: 宋体;">：测试程序的类型（</span><span style="font-size: 12pt;" lang="EN-US">Local</span><span style="font-size: 12pt; font-family: 宋体;">：本地程序、</span><span style="font-size: 12pt;" lang="EN-US">Remote</span><span style="font-size: 12pt; font-family: 宋体;">：远程程序、</span><span style="font-size: 12pt;" lang="EN-US">Applet</span><span style="font-size: 12pt; font-family: 宋体;">：</span><span style="font-size: 12pt;" lang="EN-US">JAVA</span><span style="font-size: 12pt; font-family: 宋体;">小程序、</span><span style="font-size: 12pt;" lang="EN-US">Web Start</span><span style="font-size: 12pt; font-family: 宋体;">：</span><span style="font-size: 12pt;" lang="EN-US">Web</span><span style="font-size: 12pt; font-family: 宋体;">程序）</span><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 6pt;"><strong><span style="font-size: 12pt;" lang="EN-US">Java VM</span></strong><span style="font-size: 12pt; font-family: 宋体;">：本地机的所安装的</span><span style="font-size: 12pt;" lang="EN-US">jre</span><span style="font-size: 12pt; font-family: 宋体;">版本。</span><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 6pt;"><strong><span style="font-size: 12pt;" lang="EN-US">Working dirctory</span></strong><span style="font-size: 12pt; font-family: 宋体;">：工作区目录。</span><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 30pt; text-indent: -24pt;"><span style="font-size: 12pt; font-family: 宋体;">注：由于本次要测试的为</span><span style="font-size: 12pt;" lang="EN-US">RCP</span><span style="font-size: 12pt; font-family: 宋体;">程序，因此要先将</span><span style="font-size: 12pt;" lang="EN-US">RCP</span><span style="font-size: 12pt; font-family: 宋体;">程序打包发行，这里的工作区目录本例来说是</span><span style="font-size: 12pt;" lang="EN-US">RCP</span><span style="font-size: 12pt; font-family: 宋体;">发行后的主目录。</span><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 6pt;"><strong><span style="font-size: 12pt;" lang="EN-US">Main class or executable JAR</span></strong><span style="font-size: 12pt; font-family: 宋体;">：程序的主类或</span><span style="font-size: 12pt;" lang="EN-US">JAR</span><span style="font-size: 12pt; font-family: 宋体;">包，当我们将</span><span style="font-size: 12pt;" lang="EN-US">RCP</span><span style="font-size: 12pt; font-family: 宋体;">程序打包发行后，会自动生成一个</span><span style="font-size: 12pt;" lang="EN-US">startup.jar</span><span style="font-size: 12pt; font-family: 宋体;">的文件，此处添写</span><span style="font-size: 12pt;" lang="EN-US">startup.jar</span><span style="font-size: 12pt; font-family: 宋体;">的完整路径。</span><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 6pt;"><span style="font-size: 12pt; font-family: 宋体;">另外，在下方的&#8220;</span><span style="font-size: 12pt;" lang="EN-US">Java File Path</span><span style="font-size: 12pt; font-family: 宋体;">&#8221;一栏中还需要添加程序源代码路径和类路径，如果不添写，在测试时便无法查看源代码。一切都添好了，单击&#8220;</span><span style="font-size: 12pt;" lang="EN-US">OK</span><span style="font-size: 12pt; font-family: 宋体;">&#8221;。</span><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 6pt;"><span style="font-size: 12pt;" lang="EN-US"><o:p>&nbsp;</o:p></span><strong><span style="font-size: 12pt;" lang="EN-US">3</span></strong><strong><span style="font-size: 12pt; font-family: 宋体;">、</span></strong><strong><span style="font-size: 12pt;" lang="EN-US">Evaluation Version</span></strong><strong><span style="font-size: 12pt; font-family: 宋体;">窗口</span></strong><strong><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></strong></p>
<p class="MsoNormal" style="margin-left: 6pt;"><span style="font-size: 12pt; font-family: 宋体;">此窗口是用来对你使用的</span><span style="font-size: 12pt;" lang="EN-US">JProfiler</span><span style="font-size: 12pt; font-family: 宋体;">的版本进行评估，通知你版本的使用期限，如图所示：</span><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 6pt;"><span style="font-size: 12pt; font-family: 宋体;">这里我们不用管它，直接单击&#8220;</span><span style="font-size: 12pt;" lang="EN-US">Evaluate</span><span style="font-size: 12pt; font-family: 宋体;">&#8221;，出现&#8220;</span><span style="font-size: 12pt;" lang="EN-US">Session Startup</span><span style="font-size: 12pt; font-family: 宋体;">&#8221;窗口如图所示：</span><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 6pt;"><span style="font-size: 12pt; font-family: 宋体;">这里显示了此次测试的一些配置信息，不用管理它，单击&#8220;</span><span style="font-size: 12pt;" lang="EN-US">OK</span><span style="font-size: 12pt; font-family: 宋体;">&#8221;，此时将会启动要测试的程序，我测试的程序是&#8220;</span><span style="font-size: 12pt;" lang="EN-US">PDM</span><span style="font-size: 12pt; font-family: 宋体;">数据管理系统&#8221;运行介面如下：</span><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 6pt;"><span style="font-size: 12pt;" lang="EN-US">4</span><span style="font-size: 12pt; font-family: 宋体;">、<strong>执行&#8220;</strong></span><strong><span style="font-size: 12pt;" lang="EN-US">PDM</span></strong><strong><span style="font-size: 12pt; font-family: 宋体;">数据管理系统&#8221;</span></strong><span style="font-size: 12pt; font-family: 宋体;">，执行&#8220;</span><span style="font-size: 12pt;" lang="EN-US">PDM</span><span style="font-size: 12pt; font-family: 宋体;">数据管理系统&#8221;中的查询操作后，</span><span style="font-size: 12pt;" lang="EN-US">JProfiler</span><span style="font-size: 12pt; font-family: 宋体;">显示的界面如图所示：</span><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 6pt;"><strong><span style="font-size: 12pt;" lang="EN-US">&nbsp;Aggregation level</span></strong><strong><span style="font-size: 12pt; font-family: 宋体;">：</span></strong><span style="font-size: 12pt; font-family: 宋体;">显示的方式，我们这里选&#8220;</span><span style="font-size: 12pt;" lang="EN-US">pacakge</span><span style="font-size: 12pt; font-family: 宋体;">&#8221;，图中的&#8220;</span><span style="font-size: 12pt;" lang="EN-US">cn.com.panyang.pmanager.model</span><span style="font-size: 12pt; font-family: 宋体;">&#8221;是我编写程序时手动创建的包，第二列&#8220;</span><span style="font-size: 12pt;" lang="EN-US">Instance count</span><span style="font-size: 12pt; font-family: 宋体;">&#8221;代表程序执行的次数。</span><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 6pt;"><span style="font-size: 12pt; font-family: 宋体;">接下来标记现在的状态，界面如图：</span><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 6pt;"><span style="font-size: 12pt; font-family: 宋体;">然后再执行一次&#8220;</span><span style="font-size: 12pt;" lang="EN-US">PDM</span><span style="font-size: 12pt; font-family: 宋体;">数据管理系统&#8221;中的查询操作（查询条件与先前的不一致），界面变为：</span><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 6pt;"><span style="font-size: 12pt; font-family: 宋体;">红色表示发生变化的对象及变化数量，其中的</span><span style="font-size: 12pt;" lang="EN-US">2142</span><span style="font-size: 12pt; font-family: 宋体;">表示两次执行的次数总和，第三列的</span><strong><span style="font-size: 12pt;" lang="EN-US">Difference</span></strong><span style="font-size: 12pt;" lang="EN-US"> </span><span style="font-size: 12pt; font-family: 宋体;">表示两次之间发生变化的数量。现在按</span><span style="font-size: 12pt;" lang="EN-US">F4</span><span style="font-size: 12pt; font-family: 宋体;">进行垃圾回收，几秒钟后我们会发现，一些类的红色不见了，证明垃圾回收得很彻底。但是，还有一些仍然存在红色区域，说明某些地方对这个类的引用没有被释放，然后我们可以以此为依据对代码进行初步优化。</span><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size: 12pt;" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal"><strong><span style="font-size: 12pt;" lang="EN-US">5</span></strong><strong><span style="font-size: 12pt; font-family: 宋体;">、查看方法消耗的时间</span></strong><strong><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></strong></p>
<p class="MsoNormal"><span style="font-size: 12pt;" lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-size: 12pt; font-family: 宋体;">在进行完以上的操后我们可以点击窗口左边的&#8220;</span><span style="font-size: 12pt;" lang="EN-US">CPU Views</span><span style="font-size: 12pt; font-family: 宋体;">&#8221;，再点击右侧窗口的&#8220;</span><span style="font-size: 12pt;" lang="EN-US">Hot Spots</span><span style="font-size: 12pt; font-family: 宋体;">&#8221;标签来查看程序运行时每个方法的消耗时间和</span><span style="font-size: 12pt;" lang="EN-US">CPU</span><span style="font-size: 12pt; font-family: 宋体;">占用比，如图：</span><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size: 12pt;" lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-size: 12pt; font-family: 宋体;">我们可以通过此图，将最耗时和</span><span style="font-size: 12pt;" lang="EN-US">CPU</span><span style="font-size: 12pt; font-family: 宋体;">占用大的代码段进行优化，缩短程序的运行时间，从而达到对系统性能的提高。</span><span style="font-size: 12pt;" lang="EN-US"><o:p></o:p></span></p>
<img src ="http://www.blogjava.net/persister/aggbug/248370.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2008-12-26 09:37 <a href="http://www.blogjava.net/persister/archive/2008/12/26/248370.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>