spring线程池的使用

2019阿里云全部产品优惠券(好东东,强烈推荐)
领取地址 https://promotion.aliyun.com/ntms/yunparter/invite.html

推荐:spring线程池的使用,spring线程池的使用

[spring线程池的使用分类: spring 2010-07-14 09:17 1931人阅读 评论(0)收藏 举报为了尽量减少耗时操作对Action执行的影响,使用TaskExecutor线程池来管理耗时任务,作为

为了尽量减少耗时操作对Action执行的影响,使用TaskExecutor线程池来管理耗时任务,作为后台进程执行,从而解决了问题。

场景:
使用了Struts和Spring,但Struts的Action并未交给Spring容器管理,Spring容器仅仅用来管理Dao。

要求:
对每个Action,实现向数据库写入Log功能,最好做到不要影响正常的操作流程 。Log的内容是此Action的请求参数,由客户端决定。

分析:
如何截获或者使得Action执行前后做写入Log动作并非关键,难点在于“不要影响正常的操作流程”。可以将Action交给Spring容器管理,利 用AOP功能将向要执行的动作添加在Action执行前后;或者为所有Action添加一含有写入Log动作的父类。
不影响正常的操作流程,最理想的状态就是实现导弹发射出去后不管的功能。即在Action执行的某个步骤中,执行一下写入Log的命令,然后继续执行后继 任务,写入Log任务让其自己去执行,无需等待返回信息。所以写入Log功能就不能与Action处于同一进程,否则Log任务会抢占资源而让 Action的后续任务处于等待状态。
势必需要启动新的进程来执行Log任务。对于一个Action还不算复杂,多个呢?启动的新进程如何管理就成了新的问题。如果解决了这个问题,原来的问题 就显得很容易了。

实现:
根据以上分析,希望有这么一个进程提供者,有这样的功能:能接受任务;当有可用线程时,任务获得调度执行;无可用资源时,任务处于等待状态;任务执行完成 之后,释放进程资源给进程管理者。这就是一个进程池的基本功能。正好Spring定义了--TaskExecutor线程池(想想Spring还真是无所 不有啊!),为各种进程池提供了统一的用户接口。
这里就不去分析各种不同线程池的功能了。简单地讲一下对上面提出要求的解决步骤:
1 定义写入Log任务;
线程池可接受的任务都必须是实现了Runable接口的类,因此定义一个写入Log的任务如下:
class LogTask implements Runnable ...{

private AccessLog accessLog = null;
private AccessLogDao accessLogDao = null;

public LogTask(AccessLog accessLog, AccessLogDao accessLogDao) ...{
this.accessLog = accessLog;
this.accessLogDao = accessLogDao;
}

public void run() ...{
accessLogDao.addLog(accessLog);
}
}其中的AccessLog是一个简单Bean,定义了需要写入的各种信息;AccessDao专门向数据库中写入AccessLog中的内容提供服务。 在new一个LogTask的时候,必须提供这两个参数。
2 实现用TaskExcutor执行写入Log任务;
首先指定TaskExcutor接口的实现者。将具体的TaskExcutor用定义的方式配置并由Spring容器管理:

class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">




可以看到,具体使用的是ThreadPoolTaskExecutor。这样更换别的线程池也比较方便。
将任务加入到进程池并执行则比较简单:
LogTask logTask = new LogTask(accessLog, accessLogDao);
taskExecutor.execute(logTask);加入任务后,进程池会根据调度算法来执行任务(调度算法也可以自定义)。
3 定义服务接口,并实现;
定义一个Action可以方便使用的接口:
public interface AccessLogService ...{

public void writeLog(HttpServletRequest request);
}它接受的参数就是包含了 客户端请求参数的HttpServletRequest。这样就不需要Action去作参数分析了,具体的工作留给AccessLogService完 成。
实现此接口: public class AccessLogServiceImpl implements AccessLogService ...{

/**//*
* (non-Javadoc)
* @see my.test.service.AccessLogService#writeLog(javax.servlet.http.HttpServletRequest)
*/
public void writeLog(HttpServletRequest request) ...{

//分析request,创建AccessLog对象
AccessLog accessLog = new AccessLog();
//以下略

推荐:Spring 线程池使用

[Spring 线程池使用 /** * */ 一个日志管理的类: 在批理更新,插入,等操作 package com.xiu.order.core.orders.impl; import java.util.List; import org.springframe

writeLog(accessLog);
}



//-------------------------------------------------------------------------

/**//**
* 写入Log信息

*
* @param accessLog
*/
private void writeLog(AccessLog accessLog) ...{

LogTask logTask = new LogTask(accessLog, accessLogDao);
taskExecutor.execute(logTask);
}

/**//** DAO */
private AccessLogDao accessLogDao = (AccessLogDao) getDaoByName("accessLogDao");

/**//** 线程池 */
private TaskExecutor taskExecutor = (TaskExecutor) getDaoByName("taskExecutor");

//-------------------------------------------------------------------------

/**//**
* 任务定义
*
*/
class LogTask implements Runnable ...{

private AccessLog accessLog = null;
private AccessLogDao accessLogDao = null;

public LogTask(AccessLog accessLog, AccessLogDao accessLogDao) ...{
this.accessLog = accessLog;
this.accessLogDao = accessLogDao;
}

public void run() ...{
accessLogDao.addLog(accessLog);
}
}
}这里的任务被作为内部类定义 的。

4 为Action加入写入Log功能。
直接使用策略模式,为所有Action添加一父类,在父类中调用写入Log功能,而具体的Action执行流程由子类决定。
public abstract class BaseAction extends Action ...{

public ActionForward execute(
ActionMapping mapping,
ActionForm actionForm,
HttpServletRequest request,
HttpServletResponse response)
throws Exception ...{

try ...{
ActionForward forward = _execute(mapping, actionForm, request, response);

} catch (Exception e) ...{
throw e;

} finally ...{
AccessLogService als = new AccessLogServiceImpl();
als.writeLog(request);
}
}

//子类必须实现此方法
public abstract ActionForward _execute( ActionMapping mapping,
ActionForm actionForm,
HttpServletRequest request,
HttpServletResponse response) throws Exception;

}子类中只需实现抽象方法_execute即可。在执行完子类的_execute之后,才会将写入Log的任务放入进程池,然后返回。具体任务何时 被执行,则由进程池管理。
通过分析执行时log可知,Action返回之后,写入Log任务才被执行。也就是说,这样做了之后,很大程度上减少了 对Action执行流程的干扰,同时还完成了比较耗时的写数据库的工作。

总结:这只是为了解决项目中的某个特殊的需求而做的,可能也不是什么好的通用的办法。但它也给我们以后解决比如需要后台执行之类的要求提供了一种可 行的方案。

相关推荐