2008年7月30日 星期三

我的Blog访问信息

真不错啊,blog流量一直在不段的上涨,为了对的起读者,还有我自己,努力

2008年7月21日 星期一

JDK1.5中的线程池使用简介2

  1. ExecutorService pool = Executors.newFixedThreadPool(4); //创建线程池 4个工作线程
  2. pool.execute(new RunnableTask()); //向任务队列添加任务,任务是一个Runnbale的实现类
  3. pool.shutdown();//停止工作线程
这样的实现方式和上一篇文章介绍的JDK1.5中的线程池使用简介(转),我对内存的使用情况做了测试,结果是:这篇文章的实现再内存上会不段的上涨,到了一个点后,JVM会做GC回收内存,根据我的测试数据来看,每次做了垃圾回收后都在50M左右.然后又继续上涨,不段的重复这个动作.
但是上片文章提到的实现方式,一直都在10M-30M直接波动.内存使用不会上涨.

JDK1.5中的线程池使用简介(转)

一、简介
线程池类为 java.util.concurrent.ThreadPoolExecutor,常用构造方法为:

ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime, TimeUnit unit,
BlockingQueue workQueue,
RejectedExecutionHandler handler)

* corePoolSize
线程池维护线程的最少数量
* maximumPoolSiz
线程池维护线程的最大数量
* keepAliveTime
线程池维护线程所允许的空闲时间
* unit
线程池维护线程所允许的空闲时间的单位
* workQueue
线程池所使用的缓冲队列
* handler
线程池对拒绝任务的处理策略

一个任务通过 execute(Runnable)方法被添加到线程池,任务就是一个 Runnable类型的对象,任务的执行方法就是 Runnable类型对象的run()方法。

当一个任务通过execute(Runnable)方法欲添加到线程池时:

* 如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
* 如果此时线程池中的数量等于 corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。
* 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。
* 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。

也就是:处理任务的优先级为:
核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。

当线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止。这样,线程池可以动态的调整池中的线程数。

unit可选的参数为java.util.concurrent.TimeUnit中的几个静态属性:
NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS。

workQueue我常用的是:java.util.concurrent.ArrayBlockingQueue

handler有四个选择:

* ThreadPoolExecutor.AbortPolicy()
抛出java.util.concurrent.RejectedExecutionException异常
* ThreadPoolExecutor.CallerRunsPolicy()
由调用者执行这个任务
* ThreadPoolExecutor.DiscardOldestPolicy()
抛弃旧的任务
* ThreadPoolExecutor.DiscardPolicy()
抛弃当前的任务

二、一般用法举例 [下载源代码]

package cn.simplelife.exercise;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TestThreadPool {
private static int produceTaskSleepTime = 2;
public static void main(String[] args) {
//构造一个线程池
ThreadPoolExecutor producerPool = new ThreadPoolExecutor(2, 4, 0,
TimeUnit.SECONDS, new ArrayBlockingQueue(3),
new ThreadPoolExecutor.DiscardOldestPolicy());

//每隔produceTaskSleepTime的时间向线程池派送一个任务。
int i=1;
while(true){
try {
Thread.sleep(produceTaskSleepTime);

String task = "task@ " + i;
System.out.println("put " + task);

producerPool.execute(new ThreadPoolTask(task));

i++;
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

package cn.simplelife.exercise;

import java.io.Serializable;

/**
* 线程池执行的任务
* @author hdpan
*/
public class ThreadPoolTask implements Runnable,Serializable{

//JDK1.5中,每个实现Serializable接口的类都推荐声明这样的一个ID
private static final long serialVersionUID = 0;

private static int consumeTaskSleepTime = 2000;
private Object threadPoolTaskData;

ThreadPoolTask(Object tasks){
this.threadPoolTaskData = tasks;
}

//每个任务的执行过程,现在是什么都没做,除了print和sleep,:)
public void run(){
System.out.println("start .."+threadPoolTaskData);
try {
//便于观察现象,等待一段时间
Thread.sleep(consumeTaskSleepTime);
} catch (Exception e) {
e.printStackTrace();
}
threadPoolTaskData = null;
}
}

对这两段程序的说明:

1. 在这段程序中,一个任务就是一个Runnable类型的对象,也就是一个ThreadPoolTask类型的对象。
2. 一般来说任务除了处理方式外,还需要处理的数据,处理的数据通过构造方法传给任务。
3. 在这段程序中,main()方法相当于一个残忍的领导,他派发出许多任务,丢给一个叫 threadPool的任劳任怨的小组来做。
* 这个小组里面队员至少有两个,如果他们两个忙不过来, 任务就被放到任务列表里面。
* 如果积压的任务过多,多到任务列表都装不下(超过3个)的时候,就雇佣新的队员来帮忙。但是基于成本的考虑,不能雇佣太多的队员, 至多只能雇佣 4个。
* 如果四个队员都在忙时,再有新的任务, 这个小组就处理不了了,任务就会被通过一种策略来处理,我们的处理方式是不停的派发, 直到接受这个任务为止(更残忍!呵呵)。
* 因为队员工作是需要成本的,如果工作很闲,闲到 3SECONDS都没有新的任务了,那么有的队员就会被解雇了,但是,为了小组的正常运转,即使工作再闲,小组的队员也不能少于两个。
4. 通过调整 produceTaskSleepTime和 consumeTaskSleepTime的大小来实现对派发任务和处理任务的速度的控制, 改变这两个值就可以观察不同速率下程序的工作情况。
5. 通过调整4中所指的数据,再加上调整任务丢弃策略, 换上其他三种策略,就可以看出不同策略下的不同处理方式。
6. 对于其他的使用方法,参看jdk的帮助,很容易理解和使用。

2008年7月19日 星期六

关于split分割字符串,空结果不能得到的问题(转)

先看源代码

  1. /**
  2. *
  3. * @author 赵学庆 www.java2000.net
  4. *
  5. */
  6. class T {
  7. public static void main(String args[]) {
  8. String num[] = new String[11];
  9. String sLine = "101494|360103660318444|2008/06/17|周润英|1292.0|3085.76|2778.28|912.91|106.0|||";
  10. num = sLine.split("\\|");
  11. int row = 1;
  12. for (String s : num) {
  13. System.out.println(row+++"="+s);
  14. }
  15. }
  16. }

运行结果为

1=101494

2=360103660318444

3=2008/06/17

4=周润英

5=1292.0

6=3085.76

7=2778.28

8=912.91

9=106.0

查看API,有一个

  1. public String[] split(String regex, int limit);

limit 参数控制应用模式的次数,从而影响结果数组的长度。

如果限制 n 大于零,那么模式至多应用 n> - 1 次,数组的长度不大于 n,并且数组的最后条目将包含除最后的匹配定界符之外的所有输入。

如果 n 非正,那么将应用模式的次数不受限制,并且数组可以为任意长度。

如果 n 为零,那么应用模式的次数不受限制,数组可以为任意长度,并且将丢弃尾部空字符串。 修改代码为

  1. /**
  2. *
  3. * @author 赵学庆 www.java2000.net
  4. *
  5. */
  6. class T {
  7. public static void main(String args[]) {
  8. String num[] = new String[11];
  9. String sLine = "101494|360103660318444|2008/06/17|周润英|1292.0|3085.76|2778.28|912.91|106.0|||";
  10. num = sLine.split("\\|",-1); // 这里使用-1作为参数
  11. int row = 1;
  12. for (String s : num) {
  13. System.out.println(row+++"="+s);
  14. }
  15. }
  16. }

运行结果

1=101494

2=360103660318444

3=2008/06/17

4=周润英

5=1292.0

6=3085.76

7=2778.28

8=912.91

9=106.0

10=

11=

12=

结果正常


转载自:http://blog.csdn.net/java2000_net/archive/2008/07/06/2618813.aspx

2008年7月17日 星期四

jconsole监控截图

从下图可以清晰的看到JVM在一段时间内的内存使用率的一个走势.从图中可以看出每隔15分钟左右就会做一次GC,当然也可以手动执GC

下图为线程监控图.


还有很多的其他的,就自己慢慢的去耍了,我就不贴了.

JVM内存监控管理,Tomcat内存的设置

JVM内存监控管理
  • 首先你要启动Tomcat,只能使用startup.bat的方式启动.
  • 启动jdk15\bin\jconsole.exe.
  • 点击连接后,出现管理界面,这个时候我们就可以对内存,线程类等进行查看
  • 可以手动执GC
tomcat自己管理内存,在startup.bat的@echo off下面添加以下代码:
set JAVA_OPTS=%JAVA_OPTS% -Dcom.sun.management.jmxremote.port=1090 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.util.logging.config.file="%CATALINA_HOME%\conf\logging.properties"

解决严重: Exception initializing page context java.lang.OutOfMemoryError: Java heap space 的方法.

设置参数JVM参数-Xms256m -Xmx256m -XX:MaxNewSize=256m -XX:MaxPermSize=256m
可以在环境变量中增加CATALINA_OPTS,值为-Xms256m -Xmx256m -XX:MaxNewSize=256m -XX:MaxPermSize=256m,当然你也可以根据实际的需要加大内存值.

因为对于操作系统,请求内存的系统调用会占用大量的cpu时间,所以频繁的请求、释放内存将会导致性能的严重下降。所以对于jvm,最好的方式就是尽量多占用内存作为heap,少释放甚至不释放空闲的heap给操作系统以减少消耗在内存请求、释放操作上的cpu时间。
PermGen space的全称是Permanent Generation space,是指内存的永久保存区域OutOfMemoryError: PermGen space从表面上看就是内存益出,解决方法也一定是加大内存。说说为什么会内存益 出:这一部分用于存放Class和Meta的信息,Class在被Load的时候被放入PermGen space区域,它和和存放Instance的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以如果你的APP会LOAD很多CLASS的话,就很可能出现PermGen space错误。这种错误常见在web服务器对JSP进行pre compile的时候。

链接:

Tomcat内存释放不了

2008年7月15日 星期二

让Hibernate支持Informix真正意义上的分页方法

这种分页方式只支持10或者10以上的版本.

建一个类InformixDialect继承org.hibernate.dialect.InformixDialect.

并重写下面几个方法useMaxForLimit();supportsLimitOffset();(String querySelect, int offset, int limit);

在Hibernate的配置中hibernate.dialect=您重写的这个类InformixDialect

具体代码见下:

import java.sql.Types;

import org.hibernate.Hibernate;

public class InformixDialect extends org.hibernate.dialect.InformixDialect {

public InformixDialect() {
super();
registerHibernateType(Types.DECIMAL, Hibernate.BIG_DECIMAL.getName());
}

public boolean useMaxForLimit() {
return false;
}

public boolean supportsLimitOffset() {
return true;
}

public String getLimitString(String querySelect, int offset, int limit) {
// if (offset>0) throw new UnsupportedOperationException("informix has
// no offset");
return new StringBuffer(querySelect.length() + 8).append(querySelect)
.insert(querySelect.toLowerCase().indexOf("select") + 6,
" skip " + offset + " first " + limit).toString();
}

}