﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-傻瓜纯洁思想里的沙子-文章分类-java</title><link>http://www2.blogjava.net/bubaishui/category/13063.html</link><description>愿意当傻瓜的人都快乐</description><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 19:28:14 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 19:28:14 GMT</pubDate><ttl>60</ttl><item><title>JAVA字符集</title><link>http://www.blogjava.net/bubaishui/articles/73970.html</link><dc:creator>哈迪尤</dc:creator><author>哈迪尤</author><pubDate>Mon, 09 Oct 2006 02:01:00 GMT</pubDate><guid>http://www.blogjava.net/bubaishui/articles/73970.html</guid><wfw:comment>http://www.blogjava.net/bubaishui/comments/73970.html</wfw:comment><comments>http://www.blogjava.net/bubaishui/articles/73970.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bubaishui/comments/commentRss/73970.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bubaishui/services/trackbacks/73970.html</trackback:ping><description><![CDATA[
		<div class="postText">
				<font color="#993300" size="2">1. 概述 <br /><br />本文主要包括以下几个方面：编码基本知识，java，系统软件，url，工具软件等。 <br /><br />在下面的描述中，将以"中文"两个字为例，经查表可以知道其GB2312编码是"d6d0 cec4"，Unicode编码为"4e2d 6587"，UTF编码就是"e4b8ad e69687"。注意，这两个字没有iso8859-1编码，但可以用iso8859-1编码来"表示"。 <br /><br />2. 编码基本知识 <br /><br />最早的编码是iso8859-1，和ascii编码相似。但为了方便表示各种各样的语言，逐渐出现了很多标准编码，重要的有如下几个。 <br /><br />2.1. iso8859-1 <br /><br />属于单字节编码，最多能表示的字符范围是0-255，应用于英文系列。比如，字母'a'的编码为0x61=97。 <br /><br />很明显，iso8859-1编码表示的字符范围很窄，无法表示中文字符。但是，由于是单字节编码，和计算机最基础的表示单位一致，所以很多时候，仍旧使用iso8859-1编码来表示。而且在很多协议上，默认使用该编码。比如，虽然"中文"两个字不存在iso8859-1编码，以gb2312编码为例，应该是"d6d0 cec4"两个字符，使用iso8859-1编码的时候则将它拆开为4个字节来表示："d6 d0 ce c4"（事实上，在进行存储的时候，也是以字节为单位处理的）。而如果是UTF编码，则是6个字节"e4 b8 ad e6 96 87"。很明显，这种表示方法还需要以另一种编码为基础。 <br /><br />2.2. GB2312/GBK <br /><br />这就是汉子的国标码，专门用来表示汉字，是双字节编码，而英文字母和iso8859-1一致（兼容iso8859-1编码）。其中gbk编码能够用来同时表示繁体字和简体字，而gb2312只能表示简体字，gbk是兼容gb2312编码的。 <br /><br />2.3. unicode <br /><br />这是最统一的编码，可以用来表示所有语言的字符，而且是定长双字节（也有四字节的）编码，包括英文字母在内。所以可以说它是不兼容iso8859-1编码的，也不兼容任何编码。不过，相对于iso8859-1编码来说，uniocode编码只是在前面增加了一个0字节，比如字母'a'为"00 61"。 <br /><br />需要说明的是，定长编码便于计算机处理（注意GB2312/GBK不是定长编码），而unicode又可以用来表示所有字符，所以在很多软件内部是使用unicode编码来处理的，比如java。 <br /><br />2.4. UTF <br /><br />考虑到unicode编码不兼容iso8859-1编码，而且容易占用更多的空间：因为对于英文字母，unicode也需要两个字节来表示。所以unicode不便于传输和存储。因此而产生了utf编码，utf编码兼容iso8859-1编码，同时也可以用来表示所有语言的字符，不过，utf编码是不定长编码，每一个字符的长度从1-6个字节不等。另外，utf编码自带简单的校验功能。一般来讲，英文字母都是用一个字节表示，而汉字使用三个字节。 <br /><br />注意，虽然说utf是为了使用更少的空间而使用的，但那只是相对于unicode编码来说，如果已经知道是汉字，则使用GB2312/GBK无疑是最节省的。不过另一方面，值得说明的是，虽然utf编码对汉字使用3个字节，但即使对于汉字网页，utf编码也会比unicode编码节省，因为网页中包含了很多的英文字符。 <br /><br />3. java对字符的处理 <br /><br />在java应用软件中，会有多处涉及到字符集编码，有些地方需要进行正确的设置，有些地方需要进行一定程度的处理。 <br /><br />3.1. getBytes(charset) <br /><br />这是java字符串处理的一个标准函数，其作用是将字符串所表示的字符按照charset编码，并以字节方式表示。注意字符串在java内存中总是按unicode编码存储的。比如"中文"，正常情况下（即没有错误的时候）存储为"4e2d 6587"，如果charset为"gbk"，则被编码为"d6d0 cec4"，然后返回字节"d6 d0 ce c4"。如果charset为"utf8"则最后是"e4 b8 ad e6 96 87"。如果是"iso8859-1"，则由于无法编码，最后返回 "3f 3f"（两个问号）。 <br /><br />3.2. new String(charset) <br /><br />这是java字符串处理的另一个标准函数，和上一个函数的作用相反，将字节数组按照charset编码进行组合识别，最后转换为unicode存储。参考上述getBytes的例子，"gbk" 和"utf8"都可以得出正确的结果"4e2d 6587"，但iso8859-1最后变成了"003f 003f"（两个问号）。 <br /><br />因为utf8可以用来表示/编码所有字符，所以new String( str.getBytes( "utf8" ), "utf8" ) === str，即完全可逆。 <br /><br />3.3. setCharacterEncoding() <br /><br />该函数用来设置http请求或者相应的编码。 <br /><br />对于request，是指提交内容的编码，指定后可以通过getParameter()则直接获得正确的字符串，如果不指定，则默认使用iso8859-1编码，需要进一步处理。参见下述"表单输入"。值得注意的是在执行setCharacterEncoding()之前，不能执行任何getParameter()。java doc上说明：This method must be called prior to reading request parameters or reading input using getReader()。而且，该指定只对POST方法有效，对GET方法无效。分析原因，应该是在执行第一个getParameter()的时候，java将会按照编码分析所有的提交内容，而后续的getParameter()不再进行分析，所以setCharacterEncoding()无效。而对于GET方法提交表单是，提交的内容在URL中，一开始就已经按照编码分析所有的提交内容，setCharacterEncoding()自然就无效。 <br /><br />对于response，则是指定输出内容的编码，同时，该设置会传递给浏览器，告诉浏览器输出内容所采用的编码。 <br /><br />3.4. 处理过程 <br /><br />下面分析两个有代表性的例子，说明java对编码有关问题的处理方法。 <br /><br />3.4.1. 表单输入 <br /><br />User input  *(gbk:d6d0 cec4)  browser  *(gbk:d6d0 cec4)  web server  iso8859-1(00d6 00d 000ce 00c4)  class，需要在class中进行处理：getbytes("iso8859-1")为d6 d0 ce c4，new String("gbk")为d6d0 cec4，内存中以unicode编码则为4e2d 6587。 <br /><br />l 用户输入的编码方式和页面指定的编码有关，也和用户的操作系统有关，所以是不确定的，上例以gbk为例。 <br /><br />l 从browser到web server，可以在表单中指定提交内容时使用的字符集，否则会使用页面指定的编码。而如果在url中直接用?的方式输入参数，则其编码往往是操作系统本身的编码，因为这时和页面无关。上述仍旧以gbk编码为例。 <br /><br />l Web server接收到的是字节流，默认时（getParameter）会以iso8859-1编码处理之，结果是不正确的，所以需要进行处理。但如果预先设置了编码（通过request. setCharacterEncoding ()），则能够直接获取到正确的结果。 <br /><br />l 在页面中指定编码是个好习惯，否则可能失去控制，无法指定正确的编码。 <br /><br />3.4.2. 文件编译 <br /><br />假设文件是gbk编码保存的，而编译有两种编码选择：gbk或者iso8859-1，前者是中文windows的默认编码，后者是linux的默认编码，当然也可以在编译时指定编码。 <br /><br />Jsp  *(gbk:d6d0 cec4)  java file  *(gbk:d6d0 cec4)  compiler read  uincode(gbk: 4e2d 6587; iso8859-1: 00d6 00d 000ce 00c4)  compiler write  utf(gbk: e4b8ad e69687; iso8859-1: *)  compiled file  unicode(gbk: 4e2d 6587; iso8859-1: 00d6 00d 000ce 00c4)  class。所以用gbk编码保存，而用iso8859-1编译的结果是不正确的。 <br /><br />class  unicode(4e2d 6587)  system.out / jsp.out  gbk(d6d0 cec4)  os console / browser。 <br /><br />l 文件可以以多种编码方式保存，中文windows下，默认为ansi/gbk。 <br /><br />l 编译器读取文件时，需要得到文件的编码，如果未指定，则使用系统默认编码。一般class文件，是以系统默认编码保存的，所以编译不会出问题，但对于jsp文件，如果在中文windows下编辑保存，而部署在英文linux下运行/编译，则会出现问题。所以需要在jsp文件中用pageEncoding指定编码。 <br /><br />l Java编译的时候会转换成统一的unicode编码处理，最后保存的时候再转换为utf编码。 <br /><br />l 当系统输出字符的时候，会按指定编码输出，对于中文windows下，System.out将使用gbk编码，而对于response（浏览器），则使用jsp文件头指定的contentType，或者可以直接为response指定编码。同时，会告诉browser网页的编码。如果未指定，则会使用iso8859-1编码。对于中文，应该为browser指定输出字符串的编码。 <br /><br />l browser显示网页的时候，首先使用response中指定的编码（jsp文件头指定的contentType最终也反映在response上），如果未指定，则会使用网页中meta项指定中的contentType。 <br /><br />3.5. 几处设置 <br /><br />对于web应用程序，和编码有关的设置或者函数如下。 <br /><br />3.5.1. jsp编译 <br /><br />指定文件的存储编码，很明显，该设置应该置于文件的开头。例如：&lt;%@page pageEncoding="GBK"%&gt;。另外，对于一般class文件，可以在编译的时候指定编码。 <br /><br />3.5.2. jsp输出 <br /><br />指定文件输出到browser是使用的编码，该设置也应该置于文件的开头。例如：&lt;%@ page contentType="text/html; charset= GBK" %&gt;。该设置和response.setCharacterEncoding("GBK")等效。 <br /><br />3.5.3. meta设置 <br /><br />指定网页使用的编码，该设置对静态网页尤其有作用。因为静态网页无法采用jsp的设置，而且也无法执行response.setCharacterEncoding()。例如：&lt;META http-equiv="Content-Type" content="text/html; charset=GBK" /&gt; <br /><br />如果同时采用了jsp输出和meta设置两种编码指定方式，则jsp指定的优先。因为jsp指定的直接体现在response中。 <br /><br />需要注意的是，apache有一个设置可以给无编码指定的网页指定编码，该指定等同于jsp的编码指定方式，所以会覆盖静态网页中的meta指定。所以有人建议关闭该设置。 <br /><br />3.5.4. form设置 <br /><br />当浏览器提交表单的时候，可以指定相应的编码。例如：&lt;form accept-charset= "gb2312"&gt;。一般不必不使用该设置，浏览器会直接使用网页的编码。 <br /><br />4. 系统软件 <br /><br />下面讨论几个相关的系统软件。 <br /><br />4.1. mysql数据库 <br /><br />很明显，要支持多语言，应该将数据库的编码设置成utf或者unicode，而utf更适合与存储。但是，如果中文数据中包含的英文字母很少，其实unicode更为适合。 <br /><br />数据库的编码可以通过mysql的配置文件设置，例如default-character-set=utf8。还可以在数据库链接URL中设置，例如： useUnicode=true&amp;characterEncoding=UTF-8。注意这两者应该保持一致，在新的sql版本里，在数据库链接URL里可以不进行设置，但也不能是错误的设置。 <br /><br />4.2. apache <br /><br />appache和编码有关的配置在httpd.conf中，例如AddDefaultCharset UTF-8。如前所述，该功能会将所有静态页面的编码设置为UTF-8，最好关闭该功能。 <br /><br />另外，apache还有单独的模块来处理网页响应头，其中也可能对编码进行设置。 <br /><br />4.3. linux默认编码 <br /><br />这里所说的linux默认编码，是指运行时的环境变量。两个重要的环境变量是LC_ALL和LANG，默认编码会影响到java URLEncode的行为，下面有描述。 <br /><br />建议都设置为"zh_CN.UTF-8"。 <br /><br />4.4. 其它 <br /><br />为了支持中文文件名，linux在加载磁盘时应该指定字符集，例如：mount /dev/hda5 /mnt/hda5/ -t ntfs -o iocharset=gb2312。 <br /><br />另外，如前所述，使用GET方法提交的信息不支持request.setCharacterEncoding()，但可以通过tomcat的配置文件指定字符集，在tomcat的server.xml文件中，形如：&lt;Connector ... URIEncoding="GBK"/&gt;。这种方法将统一设置所有请求，而不能针对具体页面进行设置，也不一定和browser使用的编码相同，所以有时候并不是所期望的。 <br /><br />5. URL地址 <br /><br />URL地址中含有中文字符是很麻烦的，前面描述过使用GET方法提交表单的情况，使用GET方法时，参数就是包含在URL中。 <br /><br />5.1. URL编码 <br /><br />对于URL中的一些特殊字符，浏览器会自动进行编码。这些字符除了"/?&amp;"等外，还包括unicode字符，比如汉子。这时的编码比较特殊。 <br /><br />IE有一个选项"总是使用UTF-8发送URL"，当该选项有效时，IE将会对特殊字符进行UTF-8编码，同时进行URL编码。如果改选项无效，则使用默认编码"GBK"，并且不进行URL编码。但是，对于URL后面的参数，则总是不进行编码，相当于UTF-8选项无效。比如"中文.html?a=中文"，当UTF-8选项有效时，将发送链接"%e4%b8%ad%e6%96%87.html?a=\x4e\x2d\x65\x87"；而UTF-8选项无效时，将发送链接"\x4e\x2d\x65\x87.html?a=\x4e\x2d\x65\x87"。注意后者前面的"中文"两个字只有4个字节，而前者却有18个字节，这主要时URL编码的原因。 <br /><br />当web server（tomcat）接收到该链接时，将会进行URL解码，即去掉"%"，同时按照ISO8859-1编码（上面已经描述，可以使用URLEncoding来设置成其它编码）识别。上述例子的结果分别是"\ue4\ub8\uad\ue6\u96\u87.html?a=\u4e\u2d\u65\u87"和"\u4e\u2d\u65\u87.html?a=\u4e\u2d\u65\u87"，注意前者前面的"中文"两个字恢复成了6个字符。这里用"\u"，表示是unicode。 <br /><br />所以，由于客户端设置的不同，相同的链接，在服务器上得到了不同结果。这个问题不少人都遇到，却没有很好的解决办法。所以有的网站会建议用户尝试关闭UTF-8选项。不过，下面会描述一个更好的处理办法。 <br /><br />5.2. rewrite <br /><br />熟悉的人都知道，apache有一个功能强大的rewrite模块，这里不描述其功能。需要说明的是该模块会自动将URL解码（去除%），即完成上述web server（tomcat）的部分功能。有相关文档介绍说可以使用[NE]参数来关闭该功能，但我试验并未成功，可能是因为版本（我使用的是apache 2.0.54）问题。另外，当参数中含有"?&amp; "等符号的时候，该功能将导致系统得不到正常结果。 <br /><br />rewrite本身似乎完全是采用字节处理的方式，而不考虑字符串的编码，所以不会带来编码问题。 <br /><br />5.3. URLEncode.encode() <br /><br />这是Java本身提供对的URL编码函数，完成的工作和上述UTF-8选项有效时浏览器所做的工作相似。值得说明的是，java已经不赞成不指定编码来使用该方法（deprecated）。应该在使用的时候增加编码指定。 <br /><br />当不指定编码的时候，该方法使用系统默认编码，这会导致软件运行结果得不确定。比如对于"中文"，当系统默认编码为"gb2312"时，结果是"%4e%2d%65%87"，而默认编码为"UTF-8"，结果却是"%e4%b8%ad%e6%96%87"，后续程序将难以处理。另外，这儿说的系统默认编码是由运行tomcat时的环境变量LC_ALL和LANG等决定的，曾经出现过tomcat重启后就出现乱码的问题，最后才郁闷的发现是因为修改修改了这两个环境变量。 <br /><br />建议统一指定为"UTF-8"编码，可能需要修改相应的程序。 <br /><br />5.4. 一个解决方案 <br /><br />上面说起过，因为浏览器设置的不同，对于同一个链接，web server收到的是不同内容，而软件系统有无法知道这中间的区别，所以这一协议目前还存在缺陷。 <br /><br />针对具体问题，不应该侥幸认为所有客户的IE设置都是UTF-8有效的，也不应该粗暴的建议用户修改IE设置，要知道，用户不可能去记住每一个web server的设置。所以，接下来的解决办法就只能是让自己的程序多一点智能：根据内容来分析编码是否UTF-8。 <br /><br />比较幸运的是UTF-8编码相当有规律，所以可以通过分析传输过来的链接内容，来判断是否是正确的UTF-8字符，如果是，则以UTF-8处理之，如果不是，则使用客户默认编码（比如"GBK"），下面是一个判断是否UTF-8的例子，如果你了解相应规律，就容易理解。 <br /><br />public static boolean isValidUtf8(byte[] b,int aMaxCount){ <br /><br />       int lLen=b.length,lCharCount=0; <br /><br />       for(int i=0;i&lt;lLen &amp;&amp; lCharCount&lt;aMaxCount;++lCharCount){ <br /><br />              byte lByte=b[i++];//to fast operation, ++ now, ready for the following for(;;) <br /><br />              if(lByte&gt;=0) continue;//&gt;=0 is normal ascii <br /><br />              if(lByte&lt;(byte)0xc0 || lByte&gt;(byte)0xfd) return false; <br /><br />              int lCount=lByte&gt;(byte)0xfc?5:lByte&gt;(byte)0xf8?4 <br /><br />                     :lByte&gt;(byte)0xf0?3:lByte&gt;(byte)0xe0?2:1; <br /><br />              if(i+lCount&gt;lLen) return false; <br /><br />              for(int j=0;j&lt;lCount;++j,++i) if(b[i]&gt;=(byte)0xc0) return false; <br /><br />       } <br /><br />       return true; <br /><br />} <br /><br />相应地，一个使用上述方法的例子如下： <br /><br />public static String getUrlParam(String aStr,String aDefaultCharset) <br /><br />throws UnsupportedEncodingException{ <br /><br />       if(aStr==null) return null; <br /><br />       byte[] lBytes=aStr.getBytes("ISO-8859-1"); <br /><br />       return new String(lBytes,StringUtil.isValidUtf8(lBytes)?"utf8":aDefaultCharset); <br /><br />} <br /><br />不过，该方法也存在缺陷，如下两方面： <br /><br />l 没有包括对用户默认编码的识别，这可以根据请求信息的语言来判断，但不一定正确，因为我们有时候也会输入一些韩文，或者其他文字。 <br /><br />l 可能会错误判断UTF-8字符，一个例子是"学习"两个字，其GBK编码是" \xd1\xa7\xcf\xb0"，如果使用上述isValidUtf8方法判断，将返回true。可以考虑使用更严格的判断方法，不过估计效果不大。 <br /><br />有一个例子可以证明google也遇到了上述问题，而且也采用了和上述相似的处理方法，比如，如果在地址栏中输入"http://www.google.com/search?hl=zh-CN&amp;newwindow=1&amp;q=学习"，google将无法正确识别，而其他汉字一般能够正常识别。 <br /><br />最后，应该补充说明一下，如果不使用rewrite规则，或者通过表单提交数据，其实并不一定会遇到上述问题，因为这时可以在提交数据时指定希望的编码。另外，中文文件名确实会带来问题，应该谨慎使用。 <br /><br />6. 其它 <br /><br />下面描述一些和编码有关的其他问题。 <br /><br />6.1. SecureCRT <br /><br />除了浏览器和控制台与编码有关外，一些客户端也很有关系。比如在使用SecureCRT连接linux时，应该让SecureCRT的显示编码（不同的session，可以有不同的编码设置）和linux的编码环境变量保持一致。否则看到的一些帮助信息，就可能是乱码。 <br /><br />另外，mysql有自己的编码设置，也应该保持和SecureCRT的显示编码一致。否则通过SecureCRT执行sql语句的时候，可能无法处理中文字符，查询结果也会出现乱码。 <br /><br />对于Utf-8文件，很多编辑器（比如记事本）会在文件开头增加三个不可见的标志字节，如果作为mysql的输入文件，则必须要去掉这三个字符。（用linux的vi保存可以去掉这三个字符）。一个有趣的现象是，在中文windows下，创建一个新txt文件，用记事本打开，输入"连通"两个字，保存，再打开，你会发现两个字没了，只留下一个小黑点。 <br /><br />6.2. 过滤器 <br /><br />如果需要统一设置编码，则通过filter进行设置是个不错的选择。在filter class中，可以统一为需要的请求或者回应设置编码。参加上述setCharacterEncoding()。这个类apache已经给出了可以直接使用的例子SetCharacterEncodingFilter。 <br /><br />6.3. POST和GET <br /><br />很明显，以POST提交信息时，URL有更好的可读性，而且可以方便的使用setCharacterEncoding()来处理字符集问题。但GET方法形成的URL能够更容易表达网页的实际内容，也能够用于收藏。 <br /><br />从统一的角度考虑问题，建议采用GET方法，这要求在程序中获得参数是进行特殊处理，而无法使用setCharacterEncoding()的便利，如果不考虑rewrite，就不存在IE的UTF-8问题，可以考虑通过设置URIEncoding来方便获取URL中的参数。 <br /><br />6.4. 简繁体编码转换 <br /><br />GBK同时包含简体和繁体编码，也就是说同一个字，由于编码不同，在GBK编码下属于两个字。有时候，为了正确取得完整的结果，应该将繁体和简体进行统一。可以考虑将UTF、GBK中的所有繁体字，转换为相应的简体字，BIG5编码的数据，也应该转化成相应的简体字。当然，仍旧以UTF编码存储。 <br /><br />例如，对于"语言 ?言"，用UTF表示为"\xE8\xAF\xAD\xE8\xA8\x80 \xE8\xAA\x9E\xE8\xA8\x80"，进行简繁体编码转换后应该是两个相同的 "\xE8\xAF\xAD\xE8\xA8\x80&gt;"。 <br /></font>
		</div>
<img src ="http://www.blogjava.net/bubaishui/aggbug/73970.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bubaishui/" target="_blank">哈迪尤</a> 2006-10-09 10:01 <a href="http://www.blogjava.net/bubaishui/articles/73970.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java多线程</title><link>http://www.blogjava.net/bubaishui/articles/73968.html</link><dc:creator>哈迪尤</dc:creator><author>哈迪尤</author><pubDate>Mon, 09 Oct 2006 01:59:00 GMT</pubDate><guid>http://www.blogjava.net/bubaishui/articles/73968.html</guid><wfw:comment>http://www.blogjava.net/bubaishui/comments/73968.html</wfw:comment><comments>http://www.blogjava.net/bubaishui/articles/73968.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bubaishui/comments/commentRss/73968.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bubaishui/services/trackbacks/73968.html</trackback:ping><description><![CDATA[ 一、理解多线程<br /><br />　　多线程是这样一种机制，它允许在程序中并发执行多个指令流，每个指令流都称为一个线程，彼此间互相独立。<br /><br />　　线程又称为轻量级进程，它和进程一样拥有独立的执行控制，由操作系统负责调度，区别在于线程没有独立的存储空间，而是和所属进程中的其它线程共享一个存储空间，这使得线程间的通信远较进程简单。<br /><br />　　多个线程的执行是并发的，也就是在逻辑上“同时”，而不管是否是物理上的“同时”。如果系统只有一个CPU，那么真正的“同时”是不可能的，但是由于CPU的速度非常快，用户感觉不到其中的区别，因此我们也不用关心它，只需要设想各个线程是同时执行即可。<br /><br />　　多线程和传统的单线程在程序设计上最大的区别在于，由于各个线程的控制流彼此独立，使得各个线程之间的代码是乱序执行的，由此带来的线程调度，同步等问题，将在以后探讨。<br /><br />　　二、在Java中实现多线程<br /><br />　　我们不妨设想，为了创建一个新的线程，我们需要做些什么？很显然，我们必须指明这个线程所要执行的代码，而这就是在Java中实现多线程我们所需要做的一切！<br /><br />　　真是神奇！Java是如何做到这一点的？通过类！作为一个完全面向对象的语言，Java提供了类java.lang.Thread来方便多线程编程，这个类提供了大量的方法来方便我们控制自己的各个线程，我们以后的讨论都将围绕这个类进行。<br /><br />　　那么如何提供给 Java 我们要线程执行的代码呢？让我们来看一看 Thread 类。Thread 类最重要的方法是run()，它为Thread类的方法start()所调用，提供我们的线程所要执行的代码。为了指定我们自己的代码，只需要覆盖它！<br /><br />　　方法一：继承 Thread 类，覆盖方法 run()，我们在创建的 Thread 类的子类中重写 run() ,加入线程所要执行的代码即可。下面是一个例子：<br /><br />　　public class MyThread extends Thread<br />　　{<br />　　int count= 1, number;<br />　　public MyThread(int num)<br />　　{<br />　　number = num;<br />　　System.out.println<br />　　("创建线程 " + number);<br />　　}<br />　　public void run() {<br />　　while(true) {<br />　　System.out.println<br />　　("线程 " + number + ":计数 " + count);<br />　　if(++count== 6) return;<br />　　}<br />　　}<br />　　public static void main(String args[])<br />　　{<br />　　for(int i = 0;<br />　　i 〈 5; i++) new MyThread(i+1).start();<br />　　}<br />　　}<br />　　<br />　　这种方法简单明了，符合大家的习惯，但是，它也有一个很大的缺点，那就是如果我们的类已经从一个类继承（如小程序必须继承自 Applet 类），则无法再继承 Thread 类，这时如果我们又不想建立一个新的类，应该怎么办呢？<br /><br />　　我们不妨来探索一种新的方法：我们不创建Thread类的子类，而是直接使用它，那么我们只能将我们的方法作为参数传递给 Thread 类的实例，有点类似回调函数。但是 Java 没有指针，我们只能传递一个包含这个方法的类的实例。<br /><br />　　那么如何限制这个类必须包含这一方法呢？当然是使用接口！（虽然抽象类也可满足，但是需要继承，而我们之所以要采用这种新方法，不就是为了避免继承带来的限制吗？）<br /><br />　　Java 提供了接口 java.lang.Runnable 来支持这种方法。<br /><br />　　方法二：实现 Runnable 接口<br /><br />　　Runnable接口只有一个方法run()，我们声明自己的类实现Runnable接口并提供这一方法，将我们的线程代码写入其中，就完成了这一部分的任务。但是Runnable接口并没有任何对线程的支持，我们还必须创建Thread类的实例，这一点通过Thread类的构造函数 public Thread(Runnable target);来实现。下面是一个例子：<br /><br />　　public class MyThread implements Runnable<br />　　{<br />　　int count= 1, number;<br />　　public MyThread(int num)<br />　　{<br />　　number = num;<br />　　System.out.println("创建线程 " + number);<br />　　}<br />　　public void run()<br />　　{<br />　　while(true)<br />　　{<br />　　System.out.println<br />　　("线程 " + number + ":计数 " + count);<br />　　if(++count== 6) return;<br />　　}<br />　　}<br />　　public static void main(String args[])<br />　　{<br />　　for(int i = 0; i 〈 5;<br />　　i++) new Thread(new MyThread(i+1)).start();<br />　　}<br />　　}<br />　　<br />　　严格地说，创建Thread子类的实例也是可行的，但是必须注意的是，该子类必须没有覆盖 Thread 类的 run 方法，否则该线程执行的将是子类的 run 方法，而不是我们用以实现Runnable 接口的类的 run 方法，对此大家不妨试验一下。<br /><br />　　使用 Runnable 接口来实现多线程使得我们能够在一个类中包容所有的代码，有利于封装，它的缺点在于，我们只能使用一套代码，若想创建多个线程并使各个线程执行不同的代码，则仍必须额外创建类，如果这样的话，在大多数情况下也许还不如直接用多个类分别继承 Thread 来得紧凑。<br /><br />　　综上所述，两种方法各有千秋，大家可以灵活运用。<br /><br />　　下面让我们一起来研究一下多线程使用中的一些问题。<br /><br />　　三、线程的四种状态<br /><br />　　1. 新状态：线程已被创建但尚未执行（start() 尚未被调用）。<br /><br />　　2. 可执行状态：线程可以执行，虽然不一定正在执行。CPU 时间随时可能被分配给该线程，从而使得它执行。<br /><br />　　3. 死亡状态：正常情况下 run() 返回使得线程死亡。调用 stop()或 destroy() 亦有同样效果，但是不被推荐，前者会产生异常，后者是强制终止，不会释放锁。<br /><br />　　4. 阻塞状态：线程不会被分配 CPU 时间，无法执行。<br /><br />　　四、线程的优先级<br /><br />　　线程的优先级代表该线程的重要程度，当有多个线程同时处于可执行状态并等待获得 CPU 时间时，线程调度系统根据各个线程的优先级来决定给谁分配 CPU 时间，优先级高的线程有更大的机会获得 CPU 时间，优先级低的线程也不是没有机会，只是机会要小一些罢了。<br /><br />　　你可以调用 Thread 类的方法 getPriority() 和 setPriority()来存取线程的优先级，线程的优先级界于1(MIN_PRIORITY)和10(MAX_PRIORITY)之间，缺省是5(NORM_PRIORITY)。<br /><br />　　五、线程的同步<br /><br />　　由于同一进程的多个线程共享同一片存储空间，在带来方便的同时，也带来了访问冲突这个严重的问题。Java语言提供了专门机制以解决这种冲突，有效避免了同一个数据对象被多个线程同时访问。<br /><br />　　由于我们可以通过 private 关键字来保证数据对象只能被方法访问，所以我们只需针对方法提出一套机制，这套机制就是 synchronized 关键字，它包括两种用法：synchronized 方法和 synchronized 块。<br /><br />　　1. synchronized 方法：通过在方法声明中加入 synchronized关键字来声明 synchronized 方法。如：<br /><br />　　public synchronized void accessVal(int newVal);<br />　　<br />　　 synchronized 方法控制对类成员变量的访问：每个类实例对应一把锁，每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行，否则所属线程阻塞，方法一旦执行，就独占该锁，直到从该方法返回时才将锁释放，此后被阻塞的线程方能获得该锁，重新进入可执行状态。<br /><br />　　这种机制确保了同一时刻对于每一个类实例，其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态（因为至多只有一个能够获得该类实例对应的锁），从而有效避免了类成员变量的访问冲突（只要所有可能访问类成员变量的方法均被声明为 synchronized）。<br /><br />　　在 Java 中，不光是类实例，每一个类也对应一把锁，这样我们也可将类的静态成员函数声明为 synchronized ，以控制其对类的静态成员变量的访问。<br /><br />　　synchronized 方法的缺陷：若将一个大的方法声明为synchronized 将会大大影响效率，典型地，若将线程类的方法 run() 声明为 synchronized ，由于在线程的整个生命期内它一直在运行，因此将导致它对本类任何 synchronized 方法的调用都永远不会成功。当然我们可以通过将访问类成员变量的代码放到专门的方法中，将其声明为 synchronized ，并在主方法中调用来解决这一问题，但是 Java 为我们提供了更好的解决办法，那就是 synchronized 块。<br /><br />　　2. synchronized 块：通过 synchronized关键字来声明synchronized 块。语法如下：<br /><br />　　synchronized(syncObject)<br />　　{<br />　　//允许访问控制的代码<br />　　}<br />　　<br />　　synchronized 块是这样一个代码块，其中的代码必须获得对象 syncObject （如前所述，可以是类实例或类）的锁方能执行，具体机制同前所述。由于可以针对任意代码块，且可任意指定上锁的对象，故灵活性较高。<br /><br />　　六、线程的阻塞<br /><br />　　为了解决对共享存储区的访问冲突，Java 引入了同步机制，现在让我们来考察多个线程对共享资源的访问，显然同步机制已经不够了，因为在任意时刻所要求的资源不一定已经准备好了被访问，反过来，同一时刻准备好了的资源也可能不止一个。为了解决这种情况下的访问控制问题，Java 引入了对阻塞机制的支持。<br /><br />　　阻塞指的是暂停一个线程的执行以等待某个条件发生（如某资源就绪），学过操作系统的同学对它一定已经很熟悉了。Java 提供了大量方法来支持阻塞，下面让我们逐一分析。<br /><br />　　1. sleep() 方法：sleep() 允许指定以毫秒为单位的一段时间作为参数，它使得线程在指定的时间内进入阻塞状态，不能得到CPU 时间，指定的时间一过，线程重新进入可执行状态。典型地，sleep() 被用在等待某个资源就绪的情形：测试发现条件不满足后，让线程阻塞一段时间后重新测试，直到条件满足为止。<br /><br />　　2. suspend() 和 resume() 方法：两个方法配套使用，suspend()使得线程进入阻塞状态，并且不会自动恢复，必须其对应的resume() 被调用，才能使得线程重新进入可执行状态。典型地，suspend() 和 resume() 被用在等待另一个线程产生的结果的情形：测试发现结果还没有产生后，让线程阻塞，另一个线程产生了结果后，调用 resume() 使其恢复。<br /><br />　　3. yield() 方法：yield() 使得线程放弃当前分得的 CPU 时间，但是不使线程阻塞，即线程仍处于可执行状态，随时可能再次分得 CPU 时间。调用 yield() 的效果等价于调度程序认为该线程已执行了足够的时间从而转到另一个线程。<br /><br />　　4. wait() 和 notify() 方法：两个方法配套使用，wait() 使得线程进入阻塞状态，它有两种形式，一种允许指定以毫秒为单位的一段时间作为参数，另一种没有参数，前者当对应的 notify() 被调用或者超出指定时间时线程重新进入可执行状态，后者则必须对应的 notify() 被调用。<br /><br />　　初看起来它们与 suspend() 和 resume() 方法对没有什么分别，但是事实上它们是截然不同的。区别的核心在于，前面叙述的所有方法，阻塞时都不会释放占用的锁（如果占用了的话），而这一对方法则相反。<br /><br />　　上述的核心区别导致了一系列的细节上的区别。<br /><br />　　首先，前面叙述的所有方法都隶属于 Thread 类，但是这一对却直接隶属于 Object 类，也就是说，所有对象都拥有这一对方法。初看起来这十分不可思议，但是实际上却是很自然的，因为这一对方法阻塞时要释放占用的锁，而锁是任何对象都具有的，调用任意对象的 wait() 方法导致线程阻塞，并且该对象上的锁被释放。<br /><br />　　而调用 任意对象的notify()方法则导致因调用该对象的 wait() 方法而阻塞的线程中随机选择的一个解除阻塞（但要等到获得锁后才真正可执行）。<br /><br />　　其次，前面叙述的所有方法都可在任何位置调用，但是这一对方法却必须在 synchronized 方法或块中调用，理由也很简单，只有在synchronized 方法或块中当前线程才占有锁，才有锁可以释放。<br /><br />　　同样的道理，调用这一对方法的对象上的锁必须为当前线程所拥有，这样才有锁可以释放。因此，这一对方法调用必须放置在这样的 synchronized 方法或块中，该方法或块的上锁对象就是调用这一对方法的对象。若不满足这一条件，则程序虽然仍能编译，但在运行时会出现 IllegalMonitorStateException 异常。<br /><br />　　wait() 和 notify() 方法的上述特性决定了它们经常和synchronized 方法或块一起使用，将它们和操作系统的进程间通信机制作一个比较就会发现它们的相似性：synchronized方法或块提供了类似于操作系统原语的功能，它们的执行不会受到多线程机制的干扰，而这一对方法则相当于 block 和wakeup 原语（这一对方法均声明为 synchronized）。<br /><br />　　它们的结合使得我们可以实现操作系统上一系列精妙的进程间通信的算法（如信号量算法），并用于解决各种复杂的线程间通信问题。关于 wait() 和 notify() 方法最后再说明两点：<br /><br />　　第一：调用 notify() 方法导致解除阻塞的线程是从因调用该对象的 wait() 方法而阻塞的线程中随机选取的，我们无法预料哪一个线程将会被选择，所以编程时要特别小心，避免因这种不确定性而产生问题。<br /><br />　　第二：除了 notify()，还有一个方法 notifyAll() 也可起到类似作用，唯一的区别在于，调用 notifyAll() 方法将把因调用该对象的 wait() 方法而阻塞的所有线程一次性全部解除阻塞。当然，只有获得锁的那一个线程才能进入可执行状态。<br /><br />　　谈到阻塞，就不能不谈一谈死锁，略一分析就能发现，suspend() 方法和不指定超时期限的 wait() 方法的调用都可能产生死锁。遗憾的是，Java 并不在语言级别上支持死锁的避免，我们在编程中必须小心地避免死锁。<br /><br />　　以上我们对 Java 中实现线程阻塞的各种方法作了一番分析，我们重点分析了 wait() 和 notify()方法，因为它们的功能最强大，使用也最灵活，但是这也导致了它们的效率较低，较容易出错。实际使用中我们应该灵活使用各种方法，以便更好地达到我们的目的。<br /><br />　　七、守护线程<br /><br />　　守护线程是一类特殊的线程，它和普通线程的区别在于它并不是应用程序的核心部分，当一个应用程序的所有非守护线程终止运行时，即使仍然有守护线程在运行，应用程序也将终止，反之，只要有一个非守护线程在运行，应用程序就不会终止。守护线程一般被用于在后台为其它线程提供服务。<br /><br />　　可以通过调用方法 isDaemon() 来判断一个线程是否是守护线程，也可以调用方法 setDaemon() 来将一个线程设为守护线程。<br /><br />　　八、线程组<br /><br />　　线程组是一个 Java 特有的概念，在 Java 中，线程组是类ThreadGroup 的对象，每个线程都隶属于唯一一个线程组，这个线程组在线程创建时指定并在线程的整个生命期内都不能更改。<br /><br />　　你可以通过调用包含 ThreadGroup 类型参数的 Thread 类构造函数来指定线程属的线程组，若没有指定，则线程缺省地隶属于名为 system 的系统线程组。<br /><br />　　在 Java 中，除了预建的系统线程组外，所有线程组都必须显式创建。在 Java 中，除系统线程组外的每个线程组又隶属于另一个线程组，你可以在创建线程组时指定其所隶属的线程组，若没有指定，则缺省地隶属于系统线程组。这样，所有线程组组成了一棵以系统线程组为根的树。<br /><br />　　Java 允许我们对一个线程组中的所有线程同时进行操作，比如我们可以通过调用线程组的相应方法来设置其中所有线程的优先级，也可以启动或阻塞其中的所有线程。<br /><br />　　Java 的线程组机制的另一个重要作用是线程安全。线程组机制允许我们通过分组来区分有不同安全特性的线程，对不同组的线程进行不同的处理，还可以通过线程组的分层结构来支持不对等安全措施的采用。<br /><br />　　Java 的 ThreadGroup 类提供了大量的方法来方便我们对线程组树中的每一个线程组以及线程组中的每一个线程进行操作。<br /><br />　　九、总结<br /><br />　　在本文中，我们讲述了 Java 多线程编程的方方面面，包括创建线程，以及对多个线程进行调度、管理。我们深刻认识到了多线程编程的复杂性，以及线程切换开销带来的多线程程序的低效性，这也促使我们认真地思考一个问题：我们是否需要多线程？何时需要多线程？<br /><br />　　多线程的核心在于多个代码块并发执行，本质特点在于各代码块之间的代码是乱序执行的。我们的程序是否需要多线程，就是要看这是否也是它的内在特点。<br /><br />　　假如我们的程序根本不要求多个代码块并发执行，那自然不需要使用多线程；假如我们的程序虽然要求多个代码块并发执行，但是却不要求乱序，则我们完全可以用一个循环来简单高效地实现，也不需要使用多线程；只有当它完全符合多线程的特点时，多线程机制对线程间通信和线程管理的强大支持才能有用武之地，这时使用多线程才是值得的。<img src ="http://www.blogjava.net/bubaishui/aggbug/73968.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bubaishui/" target="_blank">哈迪尤</a> 2006-10-09 09:59 <a href="http://www.blogjava.net/bubaishui/articles/73968.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>RETE算法的描述</title><link>http://www.blogjava.net/bubaishui/articles/63242.html</link><dc:creator>哈迪尤</dc:creator><author>哈迪尤</author><pubDate>Sat, 12 Aug 2006 11:55:00 GMT</pubDate><guid>http://www.blogjava.net/bubaishui/articles/63242.html</guid><wfw:comment>http://www.blogjava.net/bubaishui/comments/63242.html</wfw:comment><comments>http://www.blogjava.net/bubaishui/articles/63242.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bubaishui/comments/commentRss/63242.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bubaishui/services/trackbacks/63242.html</trackback:ping><description><![CDATA[
		<hr />
		<div id="content_main">
				<!--正文开始-->
				<div>通过一周左右的研究，对规则引擎有了一定的了解。现在写点东西跟大家一起交流，本文主要针对RETE算法进行描述。我的文笔不太好，如果有什么没讲明白的或是说错的地方，请给我留言。</div>
				<div>首先申明，我的帖子借鉴了网上很流行的一篇帖子，好像是来自CSDN；还有一点，我不想做太多的名词解释，因为我也不是个研究很深的人，定义的不好怕被笑话。</div>
				<div>好现在我们开始。</div>
				<div>首先介绍一些网上对于规则引擎比较好的帖子。</div>
				<div>1、 来自JAVA视频网 </div>
				<div>
						<a href="http://forum.javaeye.com/viewtopic.php?t=7803&amp;postdays=0&amp;postorder=asc&amp;start=0">http://forum.javaeye.com/viewtopic.php?t=7803&amp;postdays=0&amp;postorder=asc&amp;start=0</a>
				</div>
				<div>2、  RETE算法的最原始的描述，我不知道在哪里找到的，想要的人可以留下E-mail</div>
				<div>3、  CMU的一位博士生的毕业论文，个人觉得非常好，我的很多观点都是来自这里的，要的人也可以给我发mail   <a href="mailto:ipointer@163.com">mailto:ipointer@163.com</a></div>
				<div> </div>
				<div>接着统一一下术语，很多资料里的术语都非常混乱。</div>
				<div>1、  facts 事实，我们实现的时候，会有一个事实库。用F表示。</div>
				<div>2、  patterns 模板，事实的一个模型，所有事实库中的事实都必须满足模板中的一个。用P表示。</div>
				<div>3、  conditions 条件,规则的组成部分。也必须满足模板库中的一条模板。用C表示。我们可以这样理解facts、patterns、conditions之间的关系。Patterns是一个接口，conditions则是实现这个接口的类，而facts是这个类的实例。</div>
				<div>4、  rules 规则，由一到多个条件构成。一般用and或or连接conditions。用R表示。</div>
				<div>5、  actions 动作，激活一条rule执行的动作。我们这里不作讨论。</div>
				<div>6、  还有一些术语，如：working-memory、production-memory，跟这里的概念大同小异。</div>
				<div>7、  还有一些，如：alpha-network、beta-network、join-node，我们下面会用到，先放一下，一会讨论。</div>
				<div> </div>
				<div>引用一下网上很流行的例子，我觉得没讲明白，我在用我的想法解释一下。</div>
				<div> </div>
				<div>假设在规则记忆中有下列三条规则</div>
				<div> </div>
				<div>if A(x) and B(x) and C(y) then add D(x)</div>
				<div>if A(x) and B(y) and D(x) then add E(x)</div>
				<div>if A(x) and B(x) and E(x) then delete A(x)</div>
				<div> </div>
				<div>RETE算法会先将规则编译成下列的树状架构排序网络</div>
				<div>
				</div>
				<div>
						<img height="289" alt="" src="http://www.cnblogs.com/images/cnblogs_com/ipointer/1.JPG" width="693" border="0" />
						<br />而工作记忆内容及顺序为{A(1)，A(2)，B(2)，B(3)，B(4)，C(5)}，当工作记忆依序进入网络后，会依序储存在符合条件的节点中，直到完全符合条件的推论规则推出推论。以上述例子而言， 最后推得D(2)。</div>
				<div> </div>
				<div>让我们来分析这个例子。</div>
				<div> </div>
				<div>模板库：（这个例子中只有一个模板，算法原描述中有不同的例子, 一般我们会用tuple,元组的形式来定义facts,patterns,condition）</div>
				<div>P: (?A , ?x)  其中的A可能代表一定的操作，如例子中的A,B,C,D,E ; x代表操作的参数。看看这个模板是不是已经可以描述所有的事实。</div>
				<div> </div>
				<div>条件库：(这里元组的第一项代表实际的操作，第二项代表形参)</div>
				<div>C1: (A , &lt;x&gt;)</div>
				<div>C2: (B , &lt;x&gt;)</div>
				<div>C3: (C , &lt;y&gt;)</div>
				<div>C4: (D , &lt;x&gt;)</div>
				<div>C5: (E , &lt;x&gt;)</div>
				<div>C6: (B , &lt;y&gt;)</div>
				<div> </div>
				<div>事实库：（第二项代表实参）</div>
				<div>F1: (A,1)</div>
				<div>F2: (A,2)</div>
				<div>F3: (B,2)</div>
				<div>F4: (B,3)</div>
				<div>F5: (B,4)</div>
				<div>F6: (C,5)</div>
				<div> </div>
				<div>       规则库：</div>
				<div>         R1: c1^c2^c3</div>
				<div>         R2: c1^c2^c4</div>
				<div>         R3: c1^c2^c5</div>
				<div> </div>
				<div>       </div>
				<div>       有人可能会质疑R1: c1^c2^c3，没有描述出，原式中：</div>
				<div>if A(x) and B(x) and C(y) then add D(x)，A=B的关系。但请仔细看一下，这一点已经在条件库中定义出来了。</div>
				<div> </div>
				<div>       下面我来描述一下，规则引擎中RETE算法的实现。</div>
				<div>       首先，我们要定一些规则，根据这些规则，我们的引擎可以编译出一个树状结构，上面的那张图中是一种简易的表现，其实在实现的时候不是这个样子的。</div>
				<div>       这就是beta-network出场的时候了，根据rules我们就可以确定beta-network，下面，我就画出本例中的beta-network，为了描述方便，我把alpha-network也画出来了。</div>
				<div>       </div>
				<div>
				</div>
				<div> <img height="504" alt="" src="http://www.cnblogs.com/images/cnblogs_com/ipointer/2.PNG" width="693" border="0" /></div>
				<div>上图中，左边的部分就是beta-network,右边是alpha-network,圆圈是join-node.</div>
				<div>从上图中，我们可以验证，在beta-network中，表现出了rules的内容，其中r1,r2,r3共享了许多BM和join-node,这是由于这些规则中有共同的部分，这样能加快match的速度。</div>
				<div>右边的alpha-network是根据事实库构建的，其中除alpha-network节点的节点都是根据每一条condition,从事实库中match过来的，这一过程是静态的，即在编译构建网络的过程中已经建立的。只要事实库是稳定的，即没有大幅度的变化，RETE算法的执行效率应该是非常高的，其原因就是已经通过静态的编译，构建了alpha-network。我们可以验证一下，满足c1的事实确实是w1,w2。</div>
				<div>下面我们就看一下，这个算法是怎么来运行的，即怎么来确定被激活的rules的。从top-node往下遍历，到一个join-node,与AM for c1的节点汇合，运行到match c1节点。此时，match c1节点的内容就是：w1,w2。继续往下，与AM for c2汇合（所有可能的组合应该是w1^w3,w1^w4,w1^w5,w2^w3,w2^w4,w2^w5），因为c1^c2要求参数相同，因此，match c1^c2的内容是：w2^w3。再继续，这里有一个扇出（fan-out），其中只有一个join-node可以被激活，因为旁边的AM只有一个非空。因此，也只有R1被激活了。</div>
				<div>解决扇出带来的效率降低的问题，我们可以使用hashtable来解决这个问题。</div>
				<div>RETE算法还有一些问题，如：facts库变化，我们怎么才能高效的重建alpha-network，同理包括rules的变化对beta-network的影响。这一部分我还没细看，到时候再贴出来吧。</div>
				<div> 帮我点一下旁边的google广告，谢谢了。<br /><br /><br />引用自：<a href="http://www.keyusoft.cn/Contentview.aspx?year=2005&amp;month=$10&amp;day=$6&amp;postid=123">http://www.keyusoft.cn/Contentview.aspx?year=2005&amp;month=$10&amp;day=$6&amp;postid=123</a></div>
		</div>
<img src ="http://www.blogjava.net/bubaishui/aggbug/63242.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bubaishui/" target="_blank">哈迪尤</a> 2006-08-12 19:55 <a href="http://www.blogjava.net/bubaishui/articles/63242.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>规则引擎</title><link>http://www.blogjava.net/bubaishui/articles/63240.html</link><dc:creator>哈迪尤</dc:creator><author>哈迪尤</author><pubDate>Sat, 12 Aug 2006 11:48:00 GMT</pubDate><guid>http://www.blogjava.net/bubaishui/articles/63240.html</guid><wfw:comment>http://www.blogjava.net/bubaishui/comments/63240.html</wfw:comment><comments>http://www.blogjava.net/bubaishui/articles/63240.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bubaishui/comments/commentRss/63240.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bubaishui/services/trackbacks/63240.html</trackback:ping><description><![CDATA[
		<span class="postbody">
				<font size="2">在javaeye论坛里，收集到<span class="name"><a name="109017"></a><font size="3"><strong>hk109</strong></font><font size="2">对于规则引擎的一些介绍：<br /><a href="http://forum.javaeye.com/viewtopic.php?t=7803&amp;postdays=0&amp;postorder=asc&amp;start=60">http://forum.javaeye.com/viewtopic.php?t=7803&amp;postdays=0&amp;postorder=asc&amp;start=60</a></font></span><br /><br /><br />先给大家贡献我收集到的JAVA的规则引擎实现。 <br />一、Drools： <br /><br />Drools是一个Bob McWhirter开发的开源项目,实现了JSR94 Rule Engine API并提供了单元测试代码。 <br /><br />应用了Rete核心算法。Drools提供了三种语义模块――Python模块，Java模块和Groovy模块。 <br /><br />站点：</font>
				<a class="postlink" href="http://drools.org/" target="_blank">
						<font size="2">http://drools.org/</font>
				</a>
				<font size="2">
						<br />Drools- 商务逻辑框架的选择： <br /><br /></font>
				<a class="postlink" href="http://www.matrix.org.cn/resource/article/44/44046_Drools+Framework+Business.html" target="_blank">
						<font size="2">http://www.matrix.org.cn/resource/article/44/44046_Drools+Framework+Business.html</font>
				</a>
				<font size="2">
						<br />
						<br />在你的企业级java应用中使用Drools： <br /><br /></font>
				<a class="postlink" href="http://www.matrix.org.cn/resource/article/43/43782_Drools.html" target="_blank">
						<font size="2">http://www.matrix.org.cn/resource/article/43/43782_Drools.html</font>
				</a>
				<font size="2">
						<br />
						<br />详解Java规则引擎与其API <br /><br /></font>
				<a class="postlink" href="http://www.360doc.com/showWeb/0/0/19281.aspx" target="_blank">
						<font size="2">http://www.360doc.com/showWeb/0/0/19281.aspx</font>
				</a>
				<font size="2">
						<br />
						<br />Ilog、Drools、Jess规则引擎的Rule Language 比对 <br /><br /></font>
				<a class="postlink" href="http://it.13520.org/ArticleView/2005-9-5/Article_View_46215.Htm" target="_blank">
						<font size="2">http://it.13520.org/ArticleView/2005-9-5/Article_View_46215.Htm</font>
				</a>
				<font size="2">
						<br />
						<br />
						<br />
						<br />
						<br />
						<br />二、Mandarax <br /><br />Mandarax是一个规则引擎的纯Java实现。它支持多类型的事实和基于反映的规则，数据库，EJB等等， <br /><br />支持XML标准(RuleML 0.<img alt="Cool" src="http://forum.javaeye.com/images/smiles/icon_cool.gif" border="0" />。它提供了一个兼容J2EE的使用反向链接的接口引擎。 <br /><br />站点：</font>
				<a class="postlink" href="http://mandarax.sourceforge.net/" target="_blank">
						<font size="2">http://mandarax.sourceforge.net/</font>
				</a>
				<font size="2">
						<br />
						<br />
						<br />
						<br />三、JESS <br /><br /></font>
				<a class="postlink" href="http://kb.csdn.net/java/Articles/200509/8c98bec5-aa3e-4307-8a2c-bed0ca3a7bcc.html" target="_blank">
						<font size="2">http://kb.csdn.net/java/Articles/200509/8c98bec5-aa3e-4307-8a2c-bed0ca3a7bcc.html</font>
				</a>
				<font size="2">
						<br />
						<br />
						<br />
						<br />四、JLisa <br /><br />JLisa是一个利用java构建商业规则的强大框架。它实现了JSR94 Rule Engine API。 <br /><br />站点：</font>
				<a class="postlink" href="http://jlisa.sourceforge.net/" target="_blank">
						<font size="2">http://jlisa.sourceforge.net/</font>
				</a>
				<font size="2">
						<br />
						<br />
						<br />
						<br />五、OpenRules <br /><br />OpenRules基于java完全开放源代码的商业规则管理框架。它有效的利用了MS Excel, Eclipse IDE 和其它java开源类库去构造，维护，部署，执行不同的复杂商业逻辑的规则引擎。 <br /><br />站点：</font>
				<a class="postlink" href="http://openrules.com/" target="_blank">
						<font size="2">http://openrules.com</font>
				</a>
				<font size="2">
						<br />
						<br />六、JEOPS <br /><br />JEOPS(The Java Embedded Object Production System)是一个基于Java的演绎法(Forward-Chaining)规则引擎.这个规则引擎被用于在Java 应用服务器,Java客户端程序,和Servlets中通过规则来提高它们的商业处理能力. <br /><br />站点：</font>
				<a class="postlink" href="http://sourceforge.net/projects/jeops/" target="_blank">
						<font size="2">http://sourceforge.net/projects/jeops/</font>
				</a>
				<font size="2">
						<br />
						<br />
						<br />
						<br />七、InfoSapient <br /><br />InfoSapient是一个开源的规则引擎.它设计用来表达,执行和维护在同一个公司中商业规则.InfoSapient基于纯Java开发,使用到MVC,Visitor,Strategy,Facade,Factory Method,Observer,Iterator等设计模式. <br /><br /><br />八、Prova language <br /><br />Prova (from Prolog+Java) is a rule-based system for Java and agent scripting and information integration extending the Mandarax engine with a proper language syntax and enhanced semantics. The language breaks new ground in combining expressive and declarative programming. It combines natural syntax and typing of Java with Prolog-style rules and database wrappers. Java calls may include both constructor and method calls as wellas access to public variables in classes. Distributed and agent programming transported via JMS or JADE protocols is based on reaction rules specified in a natural syntax. The language makes it easy for agents to engage in concurrent conversations without starting new threads by using reaction and novel inline reaction rules in a very natural and ecoonomic syntax, directly capturing conversations as state machines. <br /><br />站点：</font>
				<a class="postlink" href="http://comas.soi.city.ac.uk/prova" target="_blank">
						<font size="2">http://comas.soi.city.ac.uk/prova</font>
				</a>
				<font size="2">
						<br />
						<br />九、Open Lexicon <br /><br />Open Lexicon is a business rules and business process management tool that rapidly develops applications for transaction and process-based applications. It includes a business rules metadata repository, a business rules engine, and a comprehensive web-based UI for managing and testing the busines rules. It also includes process management tools for orchestrating complex interactions within business rules and business objects. <br /><br />站点：</font>
				<a class="postlink" href="http://openlexicon.org/" target="_blank">
						<font size="2">http://openlexicon.org</font>
				</a>
				<font size="2">
						<br />
						<br />十、Prova <br /><br />A Language for Rule Based Java Scripting, Information Integration, and Agent Programming <br /><br />站点：</font>
				<a class="postlink" href="http://www.prova.ws/" target="_blank">
						<font size="2">http://www.prova.ws/</font>
				</a>
				<font size="2">
						<br />
						<br />十一、Euler <br /><br />Euler is an inference engine supporting logic based proofs. It is a backward-chaining reasoner enhanced with Euler path detection. There is a 100% Java version, a C# version and a Python version. <br /><br />站点：</font>
				<a class="postlink" href="http://www.agfa.com/w3c/euler/" target="_blank">
						<font size="2">http://www.agfa.com/w3c/euler/</font>
				</a>
		</span>
<img src ="http://www.blogjava.net/bubaishui/aggbug/63240.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bubaishui/" target="_blank">哈迪尤</a> 2006-08-12 19:48 <a href="http://www.blogjava.net/bubaishui/articles/63240.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>