`

spring线程池的使用

 
阅读更多

为了尽量减少耗时操作对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容器管理:
<bean id="taskExecutor"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="2" />
<property name="keepAliveSeconds" value="200" />
<property name="maxPoolSize" value="10" />
<property name="queueCapacity" value="60" />
</bean>可以看到,具体使用的是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();
//以下略

writeLog(accessLog);
}



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

/**//**
* 写入Log信息<br>
*
* @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执行流程的干扰,同时还完成了比较耗时的写数据库的工作。

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

分享到:
评论

相关推荐

    spring 线程池实例

    配置Spring线程池主要涉及以下几个核心属性: 1. `corePoolSize`:核心线程数,即线程池维护线程的最少数量。即使在空闲时,线程池也会保留这些线程,不进行销毁。 2. `maximumPoolSize`:最大线程数,线程池能容纳...

    springmvc+spring线程池处理http并发请求数据同步控制问题

    总结,使用Spring MVC和Spring线程池处理HTTP并发请求,能够有效提升系统的并发处理能力。同时,通过数据同步控制策略,可以确保在多线程环境下数据的正确性和一致性。在实际开发中,我们需要结合业务需求,灵活运用...

    spring 线程池

    标题中的“Spring线程池”指的是Spring框架中提供的线程池实现,它是Spring对Java的ExecutorService接口的一个封装,提供了更高级别的抽象和扩展性。线程池在多线程编程中扮演着至关重要的角色,它能有效地管理和...

    ActiveMQ与Spring线程池整合实例

    ActiveMQ与Spring线程池整合的一个实例。 lib库没有上传。 对于实例的讲解,在竹子的论坛有我对这个实例的帖子(http://www.java2000.net/viewthread.jsp?tid=1167) lib中包含: apache-activemq-4.1.1.jar ...

    spring线程池(同步、异步).docx

    以下是关于Spring线程池(同步、异步)的详细解析: 一、Spring异步线程池类图 Spring提供了一系列的`TaskExecutor`实现,它们根据不同的需求和场景有不同的特性和行为。这些实现包括但不限于: 1. `...

    Spring线程池配置

    数据库连接是一种关键的有限的昂贵的资源,这一点在多用户网页应用程序中体现的尤为突出。对数据库连接的管理能显著影响到整个应用的伸缩性和健壮性,影响到程序的性能指标。

    spring线程池ThreadPoolExecutor配置以及FutureTask的使用

    在Java的多线程编程中,Spring框架提供了一种便捷的方式来管理和配置线程池,这就是`ThreadPoolTaskExecutor`。这个类是Spring对Java内置的`java.util.concurrent.ThreadPoolExecutor`的封装,允许开发者在Spring...

    Spring基于线程池的定时任务线挰异常实践

    总结来说,这篇博文探讨了如何在Spring中使用线程池执行定时任务,包括配置线程池、创建定时任务、异常处理和线程安全。同时,提到了Spring MVC在Web开发中的角色,以及它如何与任务调度协同工作。理解和掌握这些...

    JDK线程池和Spring线程池的使用实例解析

    JDK线程池和Spring线程池的使用实例解析 JDK线程池和Spring线程池是两种常用的线程池实现,它们都提供了线程池的功能,但它们在使用和配置上有所不同。下面我们将详细介绍JDK线程池和Spring线程池的使用实例解析。 ...

    Spring线程池demo

    本文将详细探讨在Spring框架中如何配置和使用线程池,并通过一个简单的示例——"Spring线程池demo"来展示其实现过程。 首先,我们需要了解线程池的基本原理。线程池通过预先创建一定数量的线程,当有任务需要执行时...

    在spring boot中使用java线程池ExecutorService的讲解

    在 Spring Boot 中使用 Java 线程池 ExecutorService 的讲解 Spring Boot 作为一个流行的 Java 框架,提供了许多便捷的功能来帮助开发者快速构建应用程序。其中之一就是使用 Java 线程池 ExecutorService 来管理...

    Spring3.2.6定时任务+线程池.docx

    ### Spring3.2.6定时任务...#### 二、Spring线程池配置 Spring框架提供了一个强大的任务调度模块,其中包含了对线程池的支持。下面通过一个具体的示例来展示如何在Spring3.2.6中配置线程池: ```xml &lt;!-- 线程池 --&gt; ...

    threadPool1.zip

    使用spring线程池多线程并发处理大批量数据,解决IO效率问题。

    Spring Boot整合FTPClient线程池的实现示例

    Spring Boot 整合 FTPClient 线程池的实现示例 在本文中,我们将探讨如何在 Spring Boot 项目中整合 FTPClient 线程池的实现示例。FTPClient 是一个常用的 FTP 客户端库,而线程池则可以帮助我们减少频繁创建和销毁...

    Spring线程池ThreadPoolTaskExecutor配置详情

    Spring线程池ThreadPoolTaskExecutor配置详情 Spring线程池ThreadPoolTaskExecutor是Spring Framework提供的一种线程池实现,用于管理和执行异步任务。本文将详细介绍ThreadPoolTaskExecutor的配置详情,并提供一...

    线程池中使用spring aop事务增强

    本篇文章将深入探讨如何在使用线程池的情况下,利用Spring AOP来增强事务处理。 首先,让我们理解问题的核心。在给定的示例中,一个服务类`AAAService`有一个`doJob`方法,它会将`job`方法提交给线程池执行。由于`...

    Java面试 spring知识点 线程池 面试题

    面试中可能会问到如何使用反射创建和调用对象,以及反射在Spring中的应用。 BeanFactory和ApplicationContext的区别是面试常考问题。BeanFactory主要关注于对象的创建和管理,而ApplicationContext则提供了更全面的...

    Spring Boot使用Spring的异步线程池的实现

    Spring Boot 使用 Spring 的异步线程池的实现 在软件开发中,异步线程池是一种非常重要的技术,能够帮助我们更好地处理系统性能和大用户量请求之间的矛盾。Spring Boot 提供了异步线程池的实现,可以帮助我们更好地...

    Spring线程池ThreadPoolExecutor配置并且得到任务执行的结果

    Spring线程池ThreadPoolExecutor配置并且得到任务执行的结果 在Java中,线程池是一种非常重要的技术,能够帮助我们更好地管理线程资源,提高系统的性能和可扩展性。其中,ThreadPoolExecutor是Java中的一种线程池...

    Spring Boot 线程池的创建、@Async 配置步骤及注意事项.docx

    在Spring Boot应用中,使用线程池和异步处理是提高系统并发性能和响应速度的重要手段。`@Async`注解是Spring提供的一个特性,用于标记方法为异步执行,这样可以避免主线程等待耗时的操作,提高系统效率。本文将详细...

Global site tag (gtag.js) - Google Analytics