﻿<?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-Raymond-文章分类-Java</title><link>http://www.blogjava.net/raymondchen625/category/7968.html</link><description>Java笔记</description><language>zh-cn</language><lastBuildDate>Wed, 28 Feb 2007 07:48:25 GMT</lastBuildDate><pubDate>Wed, 28 Feb 2007 07:48:25 GMT</pubDate><ttl>60</ttl><item><title>【转贴】 Java的秘密：将应用程序的设定存在哪里? </title><link>http://www.blogjava.net/raymondchen625/articles/33869.html</link><dc:creator>Raymond的Java笔记</dc:creator><author>Raymond的Java笔记</author><pubDate>Mon, 06 Mar 2006 07:57:00 GMT</pubDate><guid>http://www.blogjava.net/raymondchen625/articles/33869.html</guid><wfw:comment>http://www.blogjava.net/raymondchen625/comments/33869.html</wfw:comment><comments>http://www.blogjava.net/raymondchen625/articles/33869.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/raymondchen625/comments/commentRss/33869.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raymondchen625/services/trackbacks/33869.html</trackback:ping><description><![CDATA[<TABLE cellSpacing=0 cellPadding=0 width="90%" border=0>
<TBODY>
<TR>
<TH class=f24><FONT color=#05006c>
<H1>Java的秘密：将应用程序的设定存在哪里?</H1></FONT></TH></TR>
<TR>
<TD>
<HR SIZE=1 bgcolor="#d9d9d9">
</TD></TR>
<TR>
<TD align=middle height=20>http://www.chinaunix.net 作者:<A href="http://bbs.chinaunix.net/viewpro.php?uid=877" target=_blank>eclipse</A>&nbsp;&nbsp;发表于：2002-09-03 15:48:04</TD></TR>
<TR>
<TD align=middle height=30>【<A href="http://bbs.chinaunix.net/post.php?action=reply&amp;fid=26&amp;tid=15962" target=_blank>发表评论</A>】【<A href="http://bbs.chinaunix.net/viewthread.php?tid=15962" target=_blank>查看原文</A>】【<A href="http://bbs.chinaunix.net/forumdisplay.php?fid=26">Java讨论区</A>】【<A href="javascript:window.close()">关闭</A>】 </TD></TR>
<TR>
<TD class=l17><FONT class=f14 id=zoom><!-- 正文begin -->
<TABLE style="TABLE-LAYOUT: fixed; WORD-WRAP: break-word" cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD><BR>Java的秘密：将应用程序的设定存在哪里?<BR><BR>我们经常需要将我们的程序中的设定，如窗口位置，开启过的文件，用户的选项设定等数据记录下来，以做便用户下一次开启程序能继续使用这些数据。<BR>以前我们通常的做法是使用Properties类，它提供以下方法:<BR>&nbsp;void&nbsp;load(InputStream&nbsp;inStream)<BR>&nbsp;void&nbsp;store(OutputStream&nbsp;out,&nbsp;String&nbsp;header)<BR>&nbsp;String&nbsp;getProperty(String&nbsp;key,&nbsp;String&nbsp;defaultValue)<BR>&nbsp;String&nbsp;getProperty(String&nbsp;key)<BR>这些方法让我们很容易的存取设定数据.<BR>另外的办法是使用ResourceBundle这个类来储存设定数据，甚至有些程序作者使用一个自定结构的文件来储存设定数据。<BR>但不管怎样，最让程序作者头痛的是：我该将这些数据保存在哪？<BR><BR>现在好了，JDK1.4为我们提供的java.util.prefs包，里面有一个Preferences类，能让以上的工作变得极其轻松!<BR>写VB程序的人常常用SaveSetting函数和getSettging来存取注册表中的用户设定数据。而Java的Preferences类也提供了类似的机制。<BR>Preferences类在不同的平台中有不同的实现方式。而在Windows平台中，Preferences是将数据保存在注册表中的，而在其它平台中的实现我就不得而知了(我对Linux等系统都不太了解).<BR>但不管怎样，都是通过相同的接口来使用的，程序作者可以不管实现细节。<BR><BR>建立Preferences对象<BR>为了区分不同的应用程序的参数项，在建立Preferences时要指定一个节点路径。<BR>Preferences是一个抽象类，提供了一系列静态方法和抽象方法来操作参数项:<BR>抽象方法:<BR>&nbsp;Preferences&nbsp;userData&nbsp;=&nbsp;Preferences.userNodeForPackage(this)&amp;#59;<BR>&nbsp;Preferences&nbsp;sysData&nbsp;=&nbsp;Preferences.systemNodeForPackage(this)&amp;#59;<BR>&nbsp;这两个方法是从指定的物件所在的包(package)返回一个节点路径，如this是javax.swing.JComponent,则返回/javax/swing<BR>静态方法:<BR>&nbsp;Preferences&nbsp;userData&nbsp;=&nbsp;Preferences.userRoot().node(&amp;quot;/com/sunway/spc&amp;quot;)&amp;#59;<BR>&nbsp;Preferences&nbsp;sysData&nbsp;=&nbsp;Preferences.systemRoot().node(&amp;quot;/com/sunway/spc&amp;quot;)&amp;#59;<BR><BR>&nbsp;以上每种方式提供了两套操作方法。其中一套是用户参数项，另一套是系统参数项。<BR>&nbsp;在Windows平台中，用户参数项在注册表中的根节点是<BR>&nbsp;HKEY_CURRENT_USER\Software\JavaSoft\Prefs<BR>&nbsp;系统参数项在注册表中的根节点是<BR>&nbsp;HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Prefs<BR>而我们指定的节点路径是位于这些根节点之下的.<BR><BR>如何读写数据<BR>Preferences提供了多种类型数据的读写方法。<BR>先来看写(put)的方法,<BR>&nbsp;put(String&nbsp;key,&nbsp;String&nbsp;value)<BR>&nbsp;putBoolean(String&nbsp;key,&nbsp;boolean&nbsp;value)<BR>&nbsp;putByteArray(String&nbsp;key,&nbsp;byte&nbsp;value[])<BR>&nbsp;putDouble(String&nbsp;key,&nbsp;double&nbsp;value)<BR>&nbsp;putFloat(String&nbsp;key,&nbsp;float&nbsp;value)<BR>&nbsp;putInt(String&nbsp;key,&nbsp;int&nbsp;value)<BR>&nbsp;putLong(String&nbsp;key,&nbsp;long&nbsp;value)<BR>下面的是读(get)的方法,<BR>&nbsp;get(String&nbsp;key,&nbsp;String&nbsp;default)<BR>&nbsp;getBoolean(String&nbsp;key,&nbsp;boolean&nbsp;default)<BR>&nbsp;getByteArray(String&nbsp;key,&nbsp;byte&nbsp;default[])<BR>&nbsp;getDouble(String&nbsp;key,&nbsp;double&nbsp;default)<BR>&nbsp;getFloat(String&nbsp;key,&nbsp;float&nbsp;default)<BR>&nbsp;getInt(String&nbsp;key,&nbsp;int&nbsp;default)<BR>&nbsp;getLong(String&nbsp;key,&nbsp;long&nbsp;default)<BR>&nbsp;注意，每一种get方法的第二个参数需要我们为它指定缺省的参数。<BR>除了以上方式之外，Preferences还允许我们将它的数据导出到一个XML文件保存，<BR>&nbsp;void&nbsp;exportNode(OutputStream&nbsp;os)<BR>&nbsp;void&nbsp;exportSubtree(OutputStream&nbsp;os)<BR>&nbsp;我们可以导出一个节点，或是导出整个子节点树.<BR><BR>Preferences的一个演示<BR>以上的讲解足可以写一个示例来看看Preferences是如何为我们工作的,看看下面的例子:<BR>import&nbsp;java.io.*&amp;#59;<BR>import&nbsp;java.util.prefs.*&amp;#59;<BR><BR>public&nbsp;class&nbsp;PrefsDemo&nbsp;{<BR>&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String&nbsp;args[])<BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;keys[]&nbsp;=<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&amp;quot;sunway&amp;quot;,&amp;quot;copyright&amp;quot;,&amp;quot;author&amp;quot;}&amp;#59;<BR>&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;values[]&nbsp;=<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&amp;quot;sunway&nbsp;technology&nbsp;company&amp;quot;,&amp;quot;copyright&nbsp;2002&amp;quot;,&amp;quot;turbochen@163.com&amp;quot;}&amp;#59;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;建立一个位于user&nbsp;root下的/com/sunway/spc节点参数项*/<BR>&nbsp;&nbsp;&nbsp;&nbsp;Preferences&nbsp;prefsdemo&nbsp;=<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Preferences.userRoot().node(&amp;quot;/com/sunway/spc&amp;quot;)&amp;#59;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;储存参数项*/<BR>&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i=0&nbsp;&amp;#59;&nbsp;i&nbsp;&lt;&nbsp;keys.length&amp;#59;&nbsp;i++)<BR>&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;prefsdemo.put(keys<U>,&nbsp;values<U>)&amp;#59;<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;导出到XML文件&nbsp;*/<BR>&nbsp;&nbsp;&nbsp;&nbsp;try<BR>&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileOutputStream&nbsp;fos&nbsp;=&nbsp;new&nbsp;FileOutputStream(&amp;quot;prefsdemo.xml&amp;quot;)&amp;#59;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;prefsdemo.exportNode(fos)&amp;#59;<BR>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(Exception&nbsp;e)<BR>&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.err.println(&amp;quot;Cannot&nbsp;export&nbsp;nodes:&nbsp;&amp;quot;&nbsp;+&nbsp;e)&amp;#59;<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;去掉注释可以清除注册表中的参数项*/<BR>/*&nbsp;&nbsp;&nbsp;&nbsp;try<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;prefsdemo.removeNode()&amp;#59;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(BackingStoreException&nbsp;e)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;*/<BR><BR>&nbsp;&nbsp;}<BR>}<BR></U></U></TD></TR></TBODY></TABLE></FONT></TD></TR></TBODY></TABLE><img src ="http://www.blogjava.net/raymondchen625/aggbug/33869.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/raymondchen625/" target="_blank">Raymond的Java笔记</a> 2006-03-06 15:57 <a href="http://www.blogjava.net/raymondchen625/articles/33869.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转贴： Java中ThreadLocal的设计与使用</title><link>http://www.blogjava.net/raymondchen625/articles/32958.html</link><dc:creator>Raymond的Java笔记</dc:creator><author>Raymond的Java笔记</author><pubDate>Wed, 01 Mar 2006 01:09:00 GMT</pubDate><guid>http://www.blogjava.net/raymondchen625/articles/32958.html</guid><wfw:comment>http://www.blogjava.net/raymondchen625/comments/32958.html</wfw:comment><comments>http://www.blogjava.net/raymondchen625/articles/32958.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/raymondchen625/comments/commentRss/32958.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raymondchen625/services/trackbacks/32958.html</trackback:ping><description><![CDATA[<SPAN class=main><FONT size=3>早在Java 1.2推出之时，Java平台中就引入了一个新的支持：java.lang.ThreadLocal，给我们在编写多线程程序时提供了一种新的选择。使用这个工具类可以很简洁地编写出优美的多线程程序，虽然ThreadLocal非常有用，但是似乎现在了解它、使用它的朋友还不多。 <BR><BR>　　 <B>ThreadLocal是什么</B><BR><BR>　　 ThreadLocal是什么呢？其实ThreadLocal并非是一个线程的本地实现版本，它并不是一个Thread，而是thread local variable（线程局部变量）。也许把它命名为ThreadLocalVar更加合适。线程局部变量（ThreadLocal）其实的功用非常简单，就是为每一个使用该变量的线程都提供一个变量值的副本，是每一个线程都可以独立地改变自己的副本，而不会和其它线程的副本冲突。从线程的角度看，就好像每一个线程都完全拥有该变量。线程局部变量并不是Java的新发明，在其它的一些语言编译器实现（如IBM XL FORTRAN）中，它在语言的层次提供了直接的支持。因为Java中没有提供在语言层次的直接支持，而是提供了一个ThreadLocal的类来提供支持，所以，在Java中编写线程局部变量的代码相对比较笨拙，这也许是线程局部变量没有在Java中得到很好的普及的一个原因吧。<BR><BR>　　 <B>ThreadLocal的设计</B><BR><BR>　　 首先看看ThreadLocal的接口：<BR><BR>　　 　Object get() ; // 返回当前线程的线程局部变量副本 protected Object initialValue(); // 返回该线程局部变量的当前线程的初始值<BR>　　　 void set(Object value); // 设置当前线程的线程局部变量副本的值<BR><BR>　　 ThreadLocal有3个方法，其中值得注意的是initialValue()，该方法是一个protected的方法，显然是为了子类重写而特意实现的。该方法返回当前线程在该线程局部变量的初始值，这个方法是一个延迟调用方法，在一个线程第1次调用get()或者set(Object)时才执行，并且仅执行1次。ThreadLocal中的确实实现直接返回一个null：<BR><BR></FONT>
<TABLE borderColor=#ffcc66 width="100%" bgColor=#b3b3b3 border=1>
<TBODY>
<TR>
<TD>protected Object initialValue() { return null; }</TD></TR></TBODY></TABLE><BR>　　ThreadLocal是如何做到为每一个线程维护变量的副本的呢？其实实现的思路很简单，在ThreadLocal类中有一个Map，用于存储每一个线程的变量的副本。比如下面的示例实现：<BR><BR>
<TABLE borderColor=#ffcc66 width="100%" bgColor=#b3b3b3 border=1>
<TBODY>
<TR>
<TD>public class ThreadLocal<BR>{<BR>　 private Map values = Collections.synchronizedMap(new HashMap());<BR>　 public Object get()<BR>　 {<BR>　　 Thread curThread = Thread.currentThread(); <BR>　　 Object o = values.get(curThread); <BR>　　 if (o == null &amp;&amp; !values.containsKey(curThread))<BR>　　 {<BR>　　　 o = initialValue();<BR>　　　 values.put(curThread, o); <BR>　　 }<BR>　　 return o; <BR>　 }<BR><BR>　 public void set(Object newValue)<BR>　 {<BR>　　 values.put(Thread.currentThread(), newValue);<BR>　 }<BR><BR>　 public Object initialValue()<BR>　 {<BR>　　 return null; <BR>　 }<BR>}</TD></TR></TBODY></TABLE><BR>　　当然，这并不是一个工业强度的实现，但JDK中的ThreadLocal的实现总体思路也类似于此。<BR><BR>　　 <B>ThreadLocal的使用</B><BR><BR>　　 如果希望线程局部变量初始化其它值，那么需要自己实现ThreadLocal的子类并重写该方法，通常使用一个内部匿名类对ThreadLocal进行子类化，比如下面的例子，SerialNum类为每一个类分配一个序号：<BR><BR>
<TABLE borderColor=#ffcc66 width="100%" bgColor=#b3b3b3 border=1>
<TBODY>
<TR>
<TD>public class SerialNum <BR>{<BR>　 // The next serial number to be assigned<BR><BR>　 private static int nextSerialNum = 0; <BR>　 private static ThreadLocal serialNum = new ThreadLocal() <BR>　 {<BR>　　 protected synchronized Object initialValue() <BR>　　 {<BR>　　　 return new Integer(nextSerialNum++);<BR>　　 }<BR>　 };<BR><BR>　 public static int get() <BR>　 {<BR>　　 return ((Integer) (serialNum.get())).intValue(); <BR>　 }<BR>}</TD></TR></TBODY></TABLE><BR>　　SerialNum类的使用将非常地简单，因为get()方法是static的，所以在需要获取当前线程的序号时，简单地调用：<BR><BR>
<TABLE borderColor=#ffcc66 width="100%" bgColor=#b3b3b3 border=1>
<TBODY>
<TR>
<TD>int serial = SerialNum.get();</TD></TR></TBODY></TABLE><BR>　　即可。<BR><BR>　　 在线程是活动的并且ThreadLocal对象是可访问的时，该线程就持有一个到该线程局部变量副本的隐含引用，当该线程运行结束后，该线程拥有的所以线程局部变量的副本都将失效，并等待垃圾收集器收集。<BR><BR>　　 <B>ThreadLocal与其它同步机制的比较</B><BR><BR>　　 ThreadLocal和其它同步机制相比有什么优势呢？ThreadLocal和其它所有的同步机制都是为了解决多线程中的对同一变量的访问冲突，在普通的同步机制中，是通过对象加锁来实现多个线程对同一变量的安全访问的。这时该变量是多个线程共享的，使用这种同步机制需要很细致地分析在什么时候对变量进行读写，什么时候需要锁定某个对象，什么时候释放该对象的锁等等很多。所有这些都是因为多个线程共享了资源造成的。ThreadLocal就从另一个角度来解决多线程的并发访问，ThreadLocal会为每一个线程维护一个和该线程绑定的变量的副本，从而隔离了多个线程的数据，每一个线程都拥有自己的变量副本，从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象，在编写多线程代码时，可以把不安全的整个变量封装进ThreadLocal，或者把该对象的特定于线程的状态封装进ThreadLocal。<BR><BR>　　 由于ThreadLocal中可以持有任何类型的对象，所以使用ThreadLocal get当前线程的值是需要进行强制类型转换。但随着新的Java版本（1.5）将模版的引入，新的支持模版参数的ThreadLocal&lt;T&gt;类将从中受益。也可以减少强制类型转换，并将一些错误检查提前到了编译期，将一定程度地简化ThreadLocal的使用。<BR><BR>　　 <B>总结</B><BR><BR>　　 当然ThreadLocal并不能替代同步机制，两者面向的问题领域不同。同步机制是为了同步多个线程对相同资源的并发访问，是为了多个线程之间进行通信的有效方式；而ThreadLocal是隔离多个线程的数据共享，从根本上就不在多个线程之间共享资源（变量），这样当然不需要对多个线程进行同步了。所以，如果你需要进行多个线程之间进行通信，则使用同步机制；如果需要隔离多个线程之间的共享冲突，可以使用ThreadLocal，这将极大地简化你的程序，使程序更加易读、简洁。<BR><BR>原文地址： <A href="http://www.pcbookcn.com/article/2364.htm">http://www.pcbookcn.com/article/2364.htm</A></SPAN><img src ="http://www.blogjava.net/raymondchen625/aggbug/32958.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/raymondchen625/" target="_blank">Raymond的Java笔记</a> 2006-03-01 09:09 <a href="http://www.blogjava.net/raymondchen625/articles/32958.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>