Wednesday 23 July 2008

排序算法 通用化设计

很多了学了各种排序算法比如 冒泡排序,快速排序,可书本上仅仅是介绍几个数字的排序,那么如何把它应用到真正的工作中呢。这事实上是一个算法的通用性设计问题。如果了解过C++ STL的人就知道这种设计思想与原理。

我们这里主要以快速排序为例子具体说明(因为我个人现在兴趣在java,所以实现都用java实现,有时间的话我会分别用C与C++实现)。

知识准备:java 语言,快速排序的实现思想

开发环境:eclipse, jdk1.6

我们先简单的回顾一下快速排序的思想(事实上这个算法并不好讲解,总之,我尽力,有不明白的可以留言或者发邮件联系我(allwefantasy@gmail.com)):

给定一个数组,int[] array={42,8,63,15,94,23,69,75,3,61,37}

这个数组便是我们需要排序的数组。

首先我们选择其中的一个数字,比方说最右边的,37,我们称之为 枢纽(为什么叫枢纽,因为英文pivot翻译过来的)。然后我们想办法把数组中比37小的放在37的左边,比它大的放在右边(我们先不管如何实现这个放置的算法,待会我们再来讨论&&注意,最后的结果是比三十七小的我们都放 在它的左边,大的都在右边,并且37的左边和右边都是无序的),于是便有这么一个数组:3,8,23,15,37,63,69,75,42,61,94(这个结果是通过一定的算法实现的,我们后面会讲,它符合我们上面的 要求。)好了,到了这一部,我们知道 ,接着我们只要排序枢纽(也就是37)左边的和又变得就可以了,37肯定已经在正确的位置,因此我们不用理会它了(原因是什么呢,用脚趾头想下)。我们用前面相同的方法,对3,8,23,15 进行排序,也就是选择15为枢纽,重复上面的步骤,肯定又能确定一个数字的真确位置,比如15的真确位置应该是3,8,15,23。接着我们再对3,8进行排序(你也许会说,这还要排序吗,一眼就能看出来已经是有序的了,但识别忘了,计算机可使很笨的,它不知道),选择8位枢纽,所以排序结果是3,8 。在对3排序(其实已经到了终止条件了,也就是只剩下一个元素)也就是最终37左边的排序结果出来了 是 3,8,15,23。同理可以推出 右边的。

好了,现在可以讲下如何将枢纽放到正确位置上的算法了

42,8,63,15,94,23,69,75,3,61,37

上面11一个数,我们随机选择一个枢纽,前面我们选择37 主要是为了编程序的方便,不然你也可以用 (int) Math.random()*11来随机选择一个。

第1步:left=0,也就是left指向数组第一个元素,也就是42

同理,right=10,指向37

第2步:left递增,如果遇到比37小的就一直递增。如果遇到比37 大的,比如第一个数字,42,那么此时left=0,停止,执行步骤3

第3步:right-1递减,如果遇到比37大的就一直 递减,如果遇到比37小的,停止,比如这里停止在3,也就是right=8,执行第4步

第4步:交换42和3 。继续执行第1步。

终止条件:如果right-left<0,那么就终止

不知道我这么讲大家时候民白了。也许有人更喜欢通过程序来弄明白算法的思想。

下面给出实现的程序:
public int partition(int left,int right,int pivot){

int leftPtr=left-1;
int rightPtr=right;
while(true){

while(pivot>array[++left]){}
while(rightPtr>0&&pivot<array[--right]){}
if(leftPtr<rightPtr)
swap(leftPtr,rightPtr);
else break;
}
swap(leftPtr,right);
return leftPtr;
}
public void swap(int left,int right)
{
int temp=array[left];
array[left]=array[right];
array[right]=temp;

}
}
好了,上面很好解决了一个枢纽放置的问题。下面该如何实现递归循环,将所有的枢纽都排列好呢

其实根据前面的分析,已经有了清晰的思路。下面我们直接用代码说明;
int size=20;
int[] array=new int[size];
public void quickSort(int left,int right){
if(right<=left)
return ;
else{
int pivot=array[right];
int leftPtr=partition(left,right,pivot);
quickSort(left,leftPtr-1);
quickSort(leftPtr+1,right);
}
}
注意前面partition函数返回的是枢纽的位置,应为枢纽已经排好序,所以不需要再排序,所以在quickSort的递归里面不包含他。
整个程序如下:

public class QuickSort {
int size=20;
int[] array=new int[size];
public void quickSort(int left,int right){
if(right<=left)
return ;
else{
int pivot=array[right];
int leftPtr=partition(left,right,pivot);
quickSort(left,leftPtr-1);
quickSort(leftPtr+1,right);
}
}
public int partition(int left,int right,int pivot){

int leftPtr=left-1;
int rightPtr=right;
while(true){

while(pivot>array[++left]){}
while(--right>0&&pivot<array[--right]){}
if(leftPtr<=rightPtr)
swap(leftPtr,rightPtr);
else break;
}
swap(leftPtr,right);
return leftPtr;
}
public void swap(int left,int right)
{
int temp=array[left];
array[left]=array[right];
array[right]=temp;

}
}

既然快速怕需算法我们回顾完了,那么我们学了这个该怎么用呢,比如 我进行排序的不一定是数字啊,可能是字母阿。而且,这些要被排序的不一定在数组里面阿,可能是在vector,Hashtable里面阿,更进步,可能是从数据库里面取出的不确定类型的数据进行排序,如前所述,这涉及到了算法的通用性设计。
我们来分析一下,我们无法通用快速排序算法是因为比较的数据类型不同,但是排序的算法的思想。
编写通用的排序代码时,面临的一个问题是必须根据对象的实际类型来执行比较运算,从而实现正确的排序,而解决方法是“将发生变化的东西同保持不变的东西分隔开”。在这里,保持不变的代码是通用的排序算法,而每次使用时都要变化的是对象的实际比较方法。
我们先来实现一个比较的接口(面向接口编程是被JAVA语言所提倡的,spring便是这种行为的有力证实着)。
interface Compare {
boolean lessThan(Object sou, Object des);
boolean lessThanOrEqual(Object sou, Object des);
}
这是一个比较类。
下面是我改写了前面的快速排序的类;
package com.hailin.www;

import java.util.Vector;

public class QuickSortVector extends Vector{
private Compare compare;
public QuickSortVector(Compare com){
this.compare=com;
}
public void sort(){
quickSort(0,size()-1);
}
public void quickSort(int left,int right){
if(right<=left)
return ;
else{
Object pivot=elementAt(right);
int leftPtr=partition(left,right,pivot);
quickSort(left,leftPtr-1);
quickSort(leftPtr+1,right);
}
}
public int partition(int left,int right,Object pivot){

int leftPtr=left-1;
int rightPtr=right;
while(true){

while(compare.lessThan(elementAt(++leftPtr), pivot)){}
while(rightPtr>0&&compare.lessThan(pivot, elementAt(--rightPtr))){}
if(leftPtr<rightPtr)
swap(leftPtr,rightPtr);
else break;
}
swap(leftPtr,right);
return leftPtr;
}
public void swap(int left,int right)
{
Object temp=elementAt(left);
setElementAt(elementAt(right), left);
setElementAt(temp, right);



}
}

事实上只要把原来int型的改称Object根类就行了。另外,虽然数组的效率比较高,但是不灵活 ,受长度限制,提供的方法少,所以这里我们继承了Vector类。所以里面的size(),elementAt(),setElementAt()方法都是从父类继承过来的。
现在我们可以清楚地看到,假设我们要比较的字符窜,我们只要实现字符窜类的Compare接口 就可以了。
下面我们来实现CompareString类。
public class CompareString implements Compare {

@Override
public boolean lessThan(Object sou, Object des) {
return ((String)sou).toLowerCase().compareTo(((String)des).toLowerCase())<0;

}

@Override
public boolean lessThanOrEqual(Object sou, Object des) {
return ((String)sou).toLowerCase().compareTo(((String)des).toLowerCase())<=0;
}

}
这里大家注意下compareTo()方法,比较此对象与指定对象的顺序,它返回的是一个整数。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。所以我们必须判断然后返回布尔值。
下面我们给出测试程序:
import java.util.Enumeration;

public class TTest {


public static void main(String[] args) {
QuickSortVector qsv= new QuickSortVector(new CompareString());
qsv.addElement("a");
qsv.addElement("M");
qsv.addElement("b");
qsv.addElement("K");
qsv.addElement("z");
qsv.addElement("y");
qsv.sort();
Enumeration e = qsv.elements();
while(e.hasMoreElements())
System.out.println(e.nextElement());




}
}
程序结果:
a
b
K
M
y
z
在写这个程序的时候自己也犯了个小错误,用单步调试 调试了半天才闹出来希望大家能够注意以下:
if(leftPtr
从上面的程序可以看出,如果要比较其他类型的对象,你只要实现相应的Compare类就可以。
这里需要注意的一点。在测试的时候 我们还有一句 qsv.sort().其实我们可以在quickSortVector类中改写elments()方法,这样封装性更好一些。同时我们可以覆盖更多的原有的父类的方法,使之更适合我们的需要。
今天就先写到这里...希望能和大家多多交流。

Sunday 20 July 2008

RSerPoolji简介与安装配置

这几天专门研究下thomas的可信赖服务器池(RSerPool).
RSserPool核心概念: 三个实体元素: Registrar: poolElement: poolUser:
两个专有协议: ENRP(Endpoint HaNdlespace Redundancy Protocol) ASAP (Aggregate Server Access Protocol)
以及一个基础协议: sctp :
下面我们来分别理解下每一个元素于协议的作用于处于什么样的位置 为了方便理解,我们直接举个具体的例子。假设这里我们正在用浏览器上网,那么我们需要连接到服务器上去。 在假设google正在使用我们的RSerPool技术。于是我们敲入www.google.com 于是我们便连接到了google的服务器。但事实上google绝对不仅仅一台服务器,而是很多台。那么假设有一个容器需要协调这么多的服务器工作,我们便有了服务器池的概念(正确,但其范围及概念更加广泛),这有点类似于连接池的概念。那么其中的每一台服务器,我们就叫他poolElement. 想推这些池元素而言,我们这些访问服务的计算机就是poolUser,即池用户。对于服务器池而言,他们需要一个协调维护者,比如存储poolElement每一个的名字或者ID ,如果哪一个当机了,又维护者决定哪一个顶上,所有便有了Registrar的概念。那么我们会想,registrar 是如何和服务器池中的poolElement通信的呢。对需要一个协议,也就是ASAP,聚合服务器访问协议(姑且这么翻译)(注:周老师的译稿我在网上始终打不开,不知什么缘故,原因是我国禁止封锁了这个网站)。一般服务器都需要冗余,Registrars 也不例理外,所以他们之间也需要协调,有协调就有通信,有通信就有协议,于是ENRP 便产生了,也即(端点处理域冗余协议。(是这样的) 我们再看看官方的解释:



The figure above shows the building blocks of the RSerPool architecture, which has been defined by the IETF RSerPool WG in [draft-ietf-rserpool-arch]. In the terminology of RSerPool a server is denoted as a Pool Element (PE). In its Pool, it is identified by its Pool Element Identifier (PE ID), a 32-bit number. The PE ID is randomly chosen upon a PE's registration to its pool. The set of all pools is denoted as the Handlespace. In older literature, it may be denoted as Namespace. This denomination has been dropped in order to avoid confusion with the Domain Name System (DNS). Each pool in a handlespace is identified by a unique Pool Handle (PH), which is represented by an arbitrary byte vector. Usually, this is an ASCII oder Unicode name of the pool, e.g. "DownloadPool" or "WebServerPool".
上面的示意图展示了RSserPool体系的结构的各个模块图。在RSerPool技术中,一个服务器都被名名为一个池元素。在其池中,每个服务器(或池元素)被32比特的PE ID 所唯一标识。PEID 由PE在相相应池注册的过程中随基产生。一系列池构成一个处理域(Handlespace).以前是叫做名字空间,但为了避免于域名系统(DNS)中的概念想混淆改为处理域。在处理域中,每一个池都由一个唯一的由任意字节向量构成的池处理(PoolHandle(PH))所标志。通常情况下,池处理是某个池ASCII的UNICODE名字。比如“下载池”或者"web服务器池“。
Each handlespace has a certain scope (e.g. an organization or company), denoted as Operation Scope. It is an explicit non-goal of RSerPool to manage the global Internet's pools within a single handlespace. Due to the limitation of operation scopes, it is possible to keep the handlespace "flat". That is, PHs do not have any hierarchy in contrast to the Domain Name System with its top-level and sub-domains. This constraint results in a significant simplification of the handlespace management.
每一个处理域都有一个确定的范围(域)(比如一个组织或者一家公司),并且被赋予一个操作域,显然在一个单一的处理域中管理全球因特网池并不是RSerPool的目标。由于控制域的限制,我们很可能去使控制域“平坦”的而非具有层次。也就是说,和域名系统相比,PHs并没有层次结构,比如顶层域含有子域。RSerPool的这种限制简化了处理域的管理。
Within an operation scope, the handlespace is managed by redundant Registrars. In literature, this component is also denoted as ENRP Server or Name Server. Since "registrar" is the most expressive term, this denotation is used in the whole document. PRs have to be redundant in order to avoid a PR to become a single point of failure (SPoF). Each PR of an operation scope is identified by its Registrar ID (PR ID), which is a 32-bit random number. It is not necessary to ensure uniqueness of PR IDs. A PR contains a complete copy of the operation scope's handlespace. PRs of an operation scope synchronize their view of the handlespace using the Endpoint HaNdlespace Redundancy Protocol (ENRP) defined in [draft-ietf-rserpool-enrp,draft-ietf-rserpool-common-param]. Older versions of this protocol use the term Endpoint Namespace Redundancy Protocol; this naming has been replaced to avoid confusion with DNS, but the abbreviation has been kept. Due to handlespace synchronization by ENRP, PRs of an operation scope are functionally equal. That is, if any of the PRs fails, each other PR is able to seamlessly replace it.
在一个操作域中,每个处理域由相应的冗余的Registrars所管理。从含义来看,这个组件也可以被称作ENRP 服务器或者名字服务器。但既然“registrar”是最能表达相应意思的一个词汇,我们在整个文档中都将使用这个词汇。PRs 为了防止出现单点失效(single point failure)必须具有冗余。操作域中的每一个PR都由一个32比特的随机数所标志,我们称作Registrar ID(PR ID).并不需要确保PR IDs的唯一性。一个 PR包含了操作域中处理域的完全拷贝。在操作域中的每个PR都同步处理域的内容通过 Endpoint HaNdlespace Redundancy Protocol(ENRP,端点处理域冗余协议)。旧版协议中使用Endpoint Namespace Redundancy Protocol,这个名字被现在的名字替换,依然是由于避免为了和DNS 想混淆,但它的缩写形式仍然是相同的。由处理域通过ENRP进行同步,一个操作域中的PRs 是功能等同的。。。也就是说PRs中的任何一个PR失效,都可由另一个PR 所代替。
Using the Aggregate Server Access Protocol (ASAP), defined in [draft-ietf-rserpool-asap,draft-ietf-rserpool-common-param] a PE can add itself to a pool or remove it from by requesting a registration or deregistration from an arbitrary PR of the operation scope. In case of successful registration, the PR chosen for registration becomes the PE's Home-PR (PR-H). A PR-H not only informs the other PRs of the operation scope about the registration or deregistration of its PEs, it also monitors the availability of its PEs by ASAP Keep-Alive messages. A keep-alive message by a PR-H has to be acknowledged by the PE within a certain time interval. If the PE fails to answer within a certain timeout, it is assumed to be dead and immediately removed from the handlespace. Furthermore, a PE is expected to re-register regularly. At a re-registration, it is also possible for the PE to change its list of transport addresses or its policy information (to be explained later).
一个PE 可以通过向相应操作于域中的任意PR 请求注册或者注销而将他自己加入或者移出服务器池,这是通过ASAP协议完成的。一旦成功注册,该台PR 就成为相应PE的 Home-PR(PR-H)(有点凹口,也就是说,PE a 向PR b 注册,那么注册成功后b 就称作a的PR-H)。一个 PR-H不仅通知其他的PRs某个PE 的注册与注销,同时也通过ASAP Keep-Alive信息来监视PE的有效性。一个Keep-Alive 信息周期性的被PR-H 发送给PE。如果PE在规定的时限内为能够回答,该PE就被PR-H认为失效,并被移出服务器池。进一步的,一个PE 也被要求周期性的从新注册。在从新注册中,PE 就有可能改变传输地址列表以及策略信息守(这将在稍后解释)。
To use the service of a pool, a client - called Pool User (PU) in RSerPool terminology - first has to request the resolution of the pool's PH to a list of PE identities at an arbitrary PR of the operation scope. This selection procedure is denoted as Handle Resolution. For the case that the requested pool is existing, the PR will select a list of PE identities according to the pool's Pool Member Selection Policy, also simply denoted as Pool Policy.
为了使用池服务,客户,也就是Pool User(PU),首先必须请求操作域中的任意一个PR对池的PH(PH也就是前面提到的pool的ID)解析并得到PE ID列表(个人认为的过程:首先PU 给任意某个PR 发送一个PH,也就是Pool 的ID,然乎由PR 进行解析,判断这个相应的池是否存在,如果存在,这根据池成员选这策略得到一张列表返还)。这个过程被称作解析处理(Handle Resolution).在池可用的情况下,PR 会根据池的池成员选择策略(简称池策略)选择一个PE ID 的列表。
Possible pool policies are e.g. a random selection (Random) or the least-loaded PE (Least Used). While in the first case it is not necessary to have any selection information (PEs are selected randomly), it is required to maintain up-to-date load information in the second case of selecting the least-loaded PE. Using an appropriate selection policy, it is e.g. possible to equally distribute the request load onto the pool's PEs.
可能的池策略是随机选择或者选择最少被加载的PE(即最少被使用原则)。第一种情况不需要任何额外的选择信息。第二种情况需要维持一个最新的加载信息。一个合适的策略是经可能的是负荷均匀的落在由每台服务器(PE)上。
After reception of a list of PE identities from a PR, a PU will write the PE information into its local cache. This cache is denoted as PU-side Cache. Out of its cache, the PU will select exactly one PE - again using the pool's selection policy - and establish a connection to it using the application's protocol, e.g. HTTP over SCTP or TCP in case of a web server. Using this connection, the service provided by the server is used. For the case that the establishment of the connection fails or the connection is aborted during service usage, a new PE can be selected by repeating the described selection procedure. If the information in the PU-side cache is not outdated, a PE identity may be directly selected from cache, skipping the effort of asking a PR for handle resolution. After re-establishing a connection with a new PE, the state of the application session has to be re-instantiated on the new PE. The procedure necessary for session resumption is denoted as Failover Procedure and is of course application-specific. For an FTP download for example, the failover procedure could mean to tell the new FTP server the file name and the last received data position. By that, the FTP server will be able to resume the download session. Since the failover procedure is highly application-dependent, it is not part of RSerPool itself, though RSerPool provides far reaching support for the implementation of arbitrary failover schemes by its Session Layer mechanisms.
在接受到PR 返回的PE ID列表后,PU会将其缓存在本地的缓存中,该缓存称为PU-side Cache.一旦缓存溢出,PU江湖再次通过池选择策略选择一个PE并且通过应用层协议建立连接,比如(应用层协议)建立在sctp 或者TCP之上的HTTP(该协议可用于web服务)。建立好连接后,那么服务器的服务将可以使用。假设建立连接失败或者在服务正在使用的时候连接被中断,那么一个新的PE将会被选择。如果PU 端的缓存信息没有过期,PE 将被直接从缓存中选取而无须重复解析过程。在与新的PE重建连接后,应用层信息也将在新的PE中重初始化。重建会话的过程被乘坐Failover过程。以FTP下载为例子,整个failover过程意味着告诉信的FTP服务器文件名字以及被传递接受数据的位置(类似于断点续传中端点的概念)。通过上面的步骤,新的FTP服务器就可以恢复下载的会话。由于failover的是高度程序独立的,应此他的实现并不是RSerPool的一个部分,尽管RSerPool在会话层提供了了任意failover模式。
To make it possible for RSerPool components to configure automatically, PRs can announce themselves via UDP over IP multicast. These announces can be received by PEs, PUs and other PRs, allowing them to learn the list of PRs currently available in the operation scope. The advantage of using IP multicast instead of broadcast is that this mechanism will also work over routers (e.g. LANs connected via a VPN) and the announces will - for the case of e.g. a switched Ethernet - only be heard and processed by stations actually interested in this information. For the case that IP multicast is not available, it is of course possible to statically configure PR addresses.
为使RSerPollP组件配置自动化,PRs通过基于IP多播UDP互相传递信息(通知)的。这些通知将被PE或者其他的PRs接受。这可以让其他的PE活PRs学习到d当前操作域中可用PRs的列表。使用IP多播而非广播主要是因为该机制可以工作在路由器上,比如基于虚拟专用网(VPN)连接的局域网(LANs)以及通知将只会被那些对这些信息感兴趣的站点解听到(比如在交换以太网中)。如果IP 多播不被支持的华,当然也可以静态配置如有地址。
下面是安装过程,这整个安装过程并不想象的那么简单。我花了三天多时间才基本装好,还有一些问题依然没有解决。
1,首先是系统要求。我装的是Ubuntu 8.04 -hardy Heron-released in April 2008,是桌面版本的。桌面用的是GNOME.KDE应该没问题。
2 ,软件要求,必须要有GCC 编译器。这个系统默认就会装,但是装的并不全,最好是通过下面两条命令。
sudo apt-get install gcc --build-essensial
sudo apt-get install g++
3 源码 glib, sctplib ,socketapi ,rsplib 准备(这是按照Thomas 安装说明中所要求的,但有问题,至少我装了两次系统都没有解决)
4 安装 glib
sudo ./configure
sudo make
sudo make install
安装没问题。但是当你安装sctplib 时候就有问题了。在检查依赖性时候会出现两种情况:
第一种,提示没哟找到glib,
第二种,提示有某一低版本却找到一高版本。
解决办法有:(最好的)直接安装GTK开发包
输入如下命令:
sudo apt-get install libgtk2.0-common libgtk2.0-dev
这样让人心烦的glib 问题就全被系统自己解决了。
第二中方法是主要是从问题的原因入手,之所以安装好glib 之后找不到glib 是应为glib 被方在了/usr/local/lib目录下,系统是默认不找这个目录的
,我们必须把他发在/usr/lib目录。(在你看些这个目录你就知道,大部分程序包都是放在/usr/lib目录下的,/usr/local/lib却是空空如也)
所以,你必须将执行这些命令
sudo ./configure --prifix=/usr
sudo make
sudo make install
第三种方案是将
/usr/local/lib 目录添加到/etc/ld.so.conf中去。
事实上我个人觉得应该作两个工作,把第一第三种方法都做一下,应为下面装的一些包也是要放在/usr/local/lib目录下的。
5 安装sctplib
这个没有什么问题。敲那三个命令就可以了。
6安装socketapi
thomas网站上提供的包似乎有问题,因为在make的时候会提示构造函数的什么问题。因此我在linuxQuestion上问了下,可爱的knudfl(http://www.linuxquestions.org/questions/linux-software-2/socketapi-compile-problems-654728/#post3211135 )提供了一个最新的下载地址:http://ppa.launchpad.net/dreibh/ubuntu/pool/main/s/socketapi/。
我编译通过没有问题。
6 安装rsplib
安装最新版本的rsplib 会提示socketapi 版本过低,但我查阅了一下,感觉前面的那个socketapi已经是最高的了,所以我换了个rsplib2.2.0版本后就能顺利依赖性检查
基本没有什么其他问题只是在使用./configure时,使用下面的命令代替
./configure --disale-kernel-sctp
否则提示你的内核没有sctp,你必须手工将sctp继承进内核,很难。应此你可以使用嗯上面我们安装的sctp.
7 单机环境测试
因为至少要三台到四太机器,所以虚拟机是不错的选择。我的博客有具体的虚拟机配置教程,其中包括安装遇到的bug修改问题。 http://coolcat-allwefantasy.blogspot.com/

(感谢周老师的批注与修改)

Wednesday 16 July 2008

(quote)some problems in java development java开发的常见问题(转载)

问题一:做数据库缓存时遇到的问题。HashMap在并发遍历时会报ConcurrentModificationException,即使使用Collections.synchronizedList把Map包起来还是会报这个异常,这个问题很简单,解决办法也简单。第一种解决办法是不要用Map的iterator来遍历,而是用Set(Map.keySet方法)的toArray方法来遍历,这种办法虽然会损耗一定的性能和内存,但比在方法前加synchronized好得多;第二种解决办法用jdk5.0以后的ConcurrentHashMap来实现。【修正:经过测试和验证,第一种方法不行,也就是并发操作MAP而且要求遍历的时候只能用ConcruuentHashMap,在此要感谢写ConcurrentHashMap的专家们。】

问题二:jfreecharts在Linux上不能显示中文,这个问题没有费多长时间就解决了,上网一搜就搞定,解决方法如下: 到网上下载一个linux下的ttf字体,本例用的是zysong.ttf 1.确认%JavaHome%/jre/lib/fonts目录下存在zysong.ttf 2.在%JavaHome%/jre/lib/fonts目录下执行"ttmkfdir -o fonts.dir"命令,重新生成fonts.dir文件 3.确认/usr/share/fonts/zh_CN/TrueType目录存在,如果不存在则mkdir创建 4.确认/usr/share/fonts/zh_CN/TrueType目录下存在zysong.ttf 5.在%JavaHome%/jre/lib目录下,执行 cp fontconfig.RedHat.3.properties.src fontconfig.properties 6.重起resin,OK。
问题三:linux下的too many open files错误,这个问题比较严重,AS4默认打开文件数是1024,如果超过这个数,resin就自动down掉了,非常恶心。解决办法如下: echo 65536 > /proc/sys/fs/file-max 编辑/etc/sysctl.conf 文件,编辑行 fs.file-max = 65536 编辑文件/etc/security/limits.conf,增加行 * - nofile 65536 用ulimit -a 查看,如果看到行open files (-n) 65536就说明对了

问题四:内存泄露,表现出来的特征是CPU占到99.9%,内存由10%左右经过几个小时后慢慢涨到50%,最后死掉。做java的人知道,这个问题非常痛苦,而且没有很好的解决办法,因为直接看代码很难看出来。我原来一直以为问题会出现在缓存上,但仔细想想apache的LRUMap不至于产生内存泄露,尤其我设置了LRUMap最大长度只有10000,10000个内存对象能有多大,后来发现是SmartUpload的问题,改成apache的FileUpload子项目就可以了。另外,我在设置jvm参数时增加了-Xmx2048m -Xms2048m -Xmn768m -Xss512k -XX:+UseParallelGC -XX:ParallelGCThreads=4 -XX:+UseParallelOldGC -XX:+UseAdaptiveSizePolicy这些参数,可以回收年老区的内存,现在比较稳定,一般内存占到27%左右就不会再涨了,可能这些参数还不是最优的,有待探索。另外查找内存泄露的软件JProbe我也玩了玩,的确看出其他代码没有明显内存泄露。【修正:上面的参数配置狗P用都没有,内存总是一直在涨。我还尝试了用其他不同方法去回收内存,结果都不太好使,直接用jvm默认的回收方式是最好的,也就是只配置两个参数-Xmx768M -Xms768M效果最好,这样java才真的可以一次性回收几百兆的内存。】

题九:hiberate配置文件的问题,配置不好的话总是会报NESTED Exception,或者多用户并发的时候报错。我想一般人都遇到过了,增加一个c3p0的配置段,尤其注意max_statements设置稍微大一点,原来我设置为100的时候10个用户同时创建记录就会出错。 org.hibernate.connection.C3P0ConnectionProvider 200 20 3600 1000 300 5 false

Sunday 13 July 2008

vmware station 6.0 在ubuntu 中 vmmon 模块编译不成功的解决办法

* unpack VMware-workstation-6.0.3
* go to vmware-distrib/lib/modules/source
* untar the file vmmon.tar (tar xvf vmmon.tar)
* cd vmmon-only/include
* edit the file vcpuset.h
* go to line 74
* change #include “asm/bitops.h” to #include “linux/bitops.h” (Because there are some changes made to the 2.6.24 kernel, it’s not possible to include bitops.h from asm and you will have to include it from the linux directory)
* go back to vmware-distrib/lib/modules/source
* remove the old vmmon.tar file (rm vmmon.tar)
* repack the new vmmon.tar file (tar cvf vmmon.tar vmmon-only)
* remove vmmon-only directory (rm -rf vmmon-only)

Now go to vmware-distrib directory and install vmware as you usualy do. It should work without a glitch.

j3d ubuntu java3d linux解决方法

if you wanna run a application based on java3d ,you should configure the environment .the first step ,download java3d from sun' website.if it a bin file,
do like this:
sudo chmod +x *.bin
sudo ./*.bin
and then bin file will be extracted in the present directory.and in the i386 dir,you will find two so files,put them in the path like:/usr/lib/jvm/jre/i386/
in the ext dir ,there would be three jar files. put them in /usr/lib/jvm/jre/ext path.
and now you can run whatever you like.
PS :
if u use eclipse to develop 3d application based on java ,and some problems occurs ,u can right click the project and choose build path item,and and external jars ,and then choose the three jar files.

something about scim 关于scim中文输入法问题

when you install ubuntu,scim have be installed .you can type :
scim -d
to start it .
if you really be pissed off by typing the command every time .you can follow these steps:
1 export XMODIFIERS="@im=SCIM
2
System--preferences--session .click on add button,type a name and then in the command field type:
scim -d
save it and close.

PS:
sometimes u will find that though you are running scim,but you cannot write with it .maybe you can try this way to fix it:
sudo synaptic
and search scim ,and remove it completely.then run the terminal,type:
sudo apt-get install scim-pinyin
and the softmanager will do the rest.but if the problem still troubles you ,maybe you can restart your computer.
当你安装完ubuntu的时候,scim已经被安装了。你可以启动它利用下面的命令:
scim -d
如果你无法容忍每次启动的时候都要敲一遍命令的话。试着作下面事情。
1 export XMODIFIERS="@im=SCIM
2
系统--首选项--会话 。单击 添加 输入名字并在命令域下输入:
scim -d
保存关闭即可
注:
有时即使启动了scim 在网页上活其他编辑文字软件中也无法使用。这个时候你可以卸载scim并且重装。方法如下:
sudo synaptic
在 synaptic 中搜索 scim ,并单击右键选择全部卸载。
接着在命令行中执行下面的命令
sudo apt-get install scim-pinyin
既可

Wednesday 9 July 2008

socketapi compile problems

socketapi compile problems

when i install socketapi-2.1.0 ,i can pass the ./configure,but when i run the make command,the following message are show:
make all-recursive
make[1]: Entering directory `/home/william/Desktop/RSerPool/socketapi-2.1.0'
Making all in socketapi
make[2]: Entering directory `/home/william/Desktop/RSerPool/socketapi-2.1.0/socketapi'
source='thread.cc' object='thread.lo' libtool=yes \
depfile='.deps/thread.Plo' tmpdepfile='.deps/thread.TPlo' \
depmode=gcc3 /bin/bash ../admin/depcomp \
/bin/bash ../libtool --mode=compile g++ -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/include/glib-1.2 -I/usr/lib/glib/include -g -O2 -DLINUX -Wall -g3 -O0 -D_REENTRANT -D_THREAD_SAFE -DSCTP_SOCKET_API -I/usr/local/include -c -o thread.lo `test -f 'thread.cc' || echo './'`thread.cc
mkdir .libs
g++ -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/include/glib-1.2 -I/usr/lib/glib/include -g -O2 -DLINUX -Wall -g3 -O0 -D_REENTRANT -D_THREAD_SAFE -DSCTP_SOCKET_API -I/usr/local/include -c thread.cc -MT thread.lo -MD -MP -MF .deps/thread.TPlo -fPIC -DPIC -o .libs/thread.o
g++ -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/include/glib-1.2 -I/usr/lib/glib/include -g -O2 -DLINUX -Wall -g3 -O0 -D_REENTRANT -D_THREAD_SAFE -DSCTP_SOCKET_API -I/usr/local/include -c thread.cc -MT thread.lo -MD -MP -MF .deps/thread.TPlo -o thread.o >/dev/null 2>&1
source='tdstrings.cc' object='tdstrings.lo' libtool=yes \
depfile='.deps/tdstrings.Plo' tmpdepfile='.deps/tdstrings.TPlo' \
depmode=gcc3 /bin/bash ../admin/depcomp \
/bin/bash ../libtool --mode=compile g++ -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/include/glib-1.2 -I/usr/lib/glib/include -g -O2 -DLINUX -Wall -g3 -O0 -D_REENTRANT -D_THREAD_SAFE -DSCTP_SOCKET_API -I/usr/local/include -c -o tdstrings.lo `test -f 'tdstrings.cc' || echo './'`tdstrings.cc
g++ -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/include/glib-1.2 -I/usr/lib/glib/include -g -O2 -DLINUX -Wall -g3 -O0 -D_REENTRANT -D_THREAD_SAFE -DSCTP_SOCKET_API -I/usr/local/include -c tdstrings.cc -MT tdstrings.lo -MD -MP -MF .deps/tdstrings.TPlo -fPIC -DPIC -o .libs/tdstrings.o
g++ -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/include/glib-1.2 -I/usr/lib/glib/include -g -O2 -DLINUX -Wall -g3 -O0 -D_REENTRANT -D_THREAD_SAFE -DSCTP_SOCKET_API -I/usr/local/include -c tdstrings.cc -MT tdstrings.lo -MD -MP -MF .deps/tdstrings.TPlo -o tdstrings.o >/dev/null 2>&1
source='synchronizable.cc' object='synchronizable.lo' libtool=yes \
depfile='.deps/synchronizable.Plo' tmpdepfile='.deps/synchronizable.TPlo' \
depmode=gcc3 /bin/bash ../admin/depcomp \
/bin/bash ../libtool --mode=compile g++ -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/include/glib-1.2 -I/usr/lib/glib/include -g -O2 -DLINUX -Wall -g3 -O0 -D_REENTRANT -D_THREAD_SAFE -DSCTP_SOCKET_API -I/usr/local/include -c -o synchronizable.lo `test -f 'synchronizable.cc' || echo './'`synchronizable.cc
g++ -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/include/glib-1.2 -I/usr/lib/glib/include -g -O2 -DLINUX -Wall -g3 -O0 -D_REENTRANT -D_THREAD_SAFE -DSCTP_SOCKET_API -I/usr/local/include -c synchronizable.cc -MT synchronizable.lo -MD -MP -MF .deps/synchronizable.TPlo -fPIC -DPIC -o .libs/synchronizable.o
In file included from /usr/include/signal.h:33,
from synchronizable.cc:44:
/usr/include/bits/sigset.h:118: error: expected constructor, destructor, or type conversion before 'int'
/usr/include/bits/sigset.h:119: error: expected constructor, destructor, or type conversion before 'int'
/usr/include/bits/sigset.h:120: error: expected constructor, destructor, or type conversion before 'int'
make[2]: *** [synchronizable.lo] Error 1
make[2]: Leaving directory `/home/william/Desktop/RSerPool/socketapi-2.1.0/socketapi'
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/home/william/Desktop/RSerPool/socketapi-2.1.0'
make: *** [all] Error 2


and this is the ./configure output:
checking for pkg-config... /usr/bin/pkg-config
checking for GLIB - version >= 2.0.0...
*** 'pkg-config --modversion glib-2.0' returned 2.16.0, but GLIB (2.16.3)
*** was found! If pkg-config was correct, then it is best
*** to remove the old version of GLib. You may also be able to fix the error
*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing
*** /etc/ld.so.conf. Make sure you have run ldconfig if that is
*** required on your system.
*** If pkg-config was wrong, set the environment variable PKG_CONFIG_PATH
*** to point to the correct configuration files
no
checking for glib-config... /usr/bin/glib-config
checking for GLIB - version >= 1.2.0... yes
configure: creating ./config.status
config.status: creating Makefile
config.status: creating socketapi/Makefile
config.status: creating cppsocketapi/Makefile
config.status: creating socket_programs/Makefile
config.status: creating cppsocket_programs/Makefile
config.status: creating scripts/Makefile
config.status: creating config.h
config.status: executing depfiles commands

The socketapi package has been configured with the following options:

Build with Maintainer Mode : yes
Build with SCTP over UDP :

sctplib libraries : /usr/local/lib/libsctplib.a
glib_LIBS : -L/usr/lib -lglib
Thread Libraries : -lpthread

CFLAGS : -g -O2 -I/usr/include/glib-1.2 -I/usr/lib/glib/include -DLINUX -Wall -g3 -O0 -D_REENTRANT -D_THREAD_SAFE -DSCTP_SOCKET_API -I/usr/local/include
CXXFLAGS : -g -O2 -DLINUX -Wall -g3 -O0 -D_REENTRANT -D_THREAD_SAFE -DSCTP_SOCKET_API -I/usr/local/include
LDFLAGS

actually,when i install sctp,there seems to be no glib,so i install glib-2.16.0.But the config setup say glib-2,16,3 was found.notice that the program will find the glib-config ,so i installed the glib-dev ,and solve that problem,but still will show the warning.and the make goes wrong. i also download the socketapi.deb package,but it says glib cannot been found and sometimes say sctp are not found ,but i had installed sctp!damn
plz,someone can fix this problem or who have installed socketapi
successfully show me steps or communicate with me.
my e-mail:allwefantasy@gmail.com
thanks.

Thursday 3 July 2008

how to set default jre

sudo update-alternatives --config java


one sentence work out . Awesome!

i love ubuntu!
there are some commands show information about jre ,jdk.


sudo update-java-alternatives
and you can add some param to show .
for example:

william@william-superstar:/VirtualWorld/eclipse$ sudo update-java-alternatives -l
[sudo] password for william:
java-6-sun 63 /usr/lib/jvm/java-6-sun

Tuesday 1 July 2008

how to uninstall eclipse java compiler

sudo apt-get remove --purge java-gcj-compat

if you wanna intall sun jdk so type this command
sudo apt-get install sun-java6-jdk

ubuntu install realplayer

.rpm and .bin are supported in official website http://www.real.com/linux.
i use alien install realplayer.rpm ,it seems to should to config script ,and when installed ,it donnot work.
so .bin is success .
sudo chmod +x Realplayer11GOLD.bin
./bin Realplayer11GOLD.bin

then like this:
william@william-superstar:~/Desktop$ ./../RealPlayer/RealPlayer11GOLD.bin
Extracting files for Helix installation........................

Welcome to the RealPlayer (11.0.0.4028) Setup for UNIX
Setup will help you get RealPlayer running on your computer.
Press [Enter] to continue...


Enter the complete path to the directory where you want
RealPlayer to be installed. You must specify the full
pathname of the directory and have write privileges to
the chosen directory.
Directory: [/home/william/Desktop/RealPlayer]: /home/william/RealPlayer/

You have selected the following RealPlayer configuration:

Destination: /home/william/RealPlayer/

Enter [F]inish to begin copying files, or [P]revious to go
back to the previous prompts: [F]: F

Copying RealPlayer files...No write-permission to /etc/profile.d ...skip.
.Succeeded.
installing application icons resource...
installing document icons resource...
..........Succeeded.
.Configuring Mozilla...
Installing .mo locale files...
Setting selinux context...
/usr/share or /usr/bin no write-permission...skip.

RealPlayer installation is complete.
Cleaning up installation files...
Done.


now ,you should goto the directory where you install the .bin .and run the realplayer in terminal.
like following:
william@william-superstar:~/RealPlayer$ ls
Bin common install.log mozilla postinst realplay RealPlayer11GOLD.bin
codecs doc LICENSE plugins README realplay.bin share
william@william-superstar:~/RealPlayer$ ./realplay

edit system file

graphical provide us the drag and drop ways to deal with files.but cause of the user permission control ,it always disappoint you.for example:u wanna move a file from /media/windowpartion to / .in command line ,it is no big deal .sudo mv /media/windowpartion / is enough.but if u wanna change graphically, maybe the popup alert will tell you: you request are denied. what we can do?
follow me :
if you are kde ,i mean ,kubuntu,type following command:
kdesudo konqueror
actually, here kongqueror is not a brower,but file manager system.now ,you can use it edit the file belongs to root.cause there is kdesudo when you run konqueror ,remenber?
if Ubuntu (Gnome)
gksudo nautilus
if dont take effect.type ATL+F2 and come into command mode,
then type:
gksudo nautilus
this would work
if Xubuntu (XFCE)
type :
gksudo thunar


at last but not least: Good luck!