对于异步处理的Tomcat 6线程池(tomcat 6 thread pool for asynch

2019-06-25 12:33发布

简短的问题: 在一个Tomcat 6应用程序-怎样才能运行(独立的)线程池?

什么是运行一个线程池的最佳解决方案?

长的问题:
我这里有一个简单的需求;
轮询一些数据的数据库,同时允许Web客户端等待一个答案(长轮询连接)。
当此数据可在数据库中,我会发送给相关客户一个答复。

这样说,我不喜欢潜入此刻任何框架( quartz scheduler可能?)。

因此,我的结论,我需要一个线程池来完成这项工作的背景。

所以,如果Thread是什么,我要使用(实际上Runnable ),其中类一样组织这一切? 是否有一个排序的ThreadPool解决方案? 任何建议?

Answer 1:

回答你的短的问题:

在JVM线程池被抽象背后java.util.concurrent.ExecutorService接口。 有此接口的不同实现,但在大多数情况下,这种接口的方法就足够了。

要创建特定的线程池,看看java.util.concurrent.Executors类: http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/Executors.html其中包含静态工厂用于创建的不同实现方法ExecutorService接口。 您可能会感兴趣newFixedThreadPool(int threadsNumber)newCachedThreadPool方法。

有关更多常规信息Executors在JVM中你可能需要阅读以下Oracle的教程: http://docs.oracle.com/javase/tutorial/essential/concurrency/executors.html

因此,使用线程池( ExecutorService )在Tomcat下,你应该做到以下几点:

0.1。 创建并注册在web.xml的实例javax.servlet.ServletContextListener接口(这会像一个入口点到你的web应用),如果它尚未完成。

0.2。 在contextInitialized(ServletContextEvent)方法,您创建的实例ExecutorService (线程池),并将其存储在ServletContext属性图,以便它可以从任何一点在你的web应用例如访问:

// following method is invoked one time, when you web application starts (is deployed)
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
    // ...
    final int numberOfThreads = ...;
    final ExecutorService threadPool = Executors.newFixedThreadPool(numberOfThreads); // starts thread pool
    final ServletContext servletContext = servletContextEvent.getServletContext();
    servletContext.setAttribute("threadPoolAlias", threadPool);
    // ...
}

// following method is invoked one time when your web application stops (is undeployed)
public void contextDestroyed(ServletContextEvent servletContextEvent) {
    // following code is just to free resources occupied by thread pool when web application is undeployed
    final ExecutorService threadPool = (ExecutorService) servletContextEvent.getServletContext().getAttribute("threadPoolAlias");
    threadPool.shutdown();
}

0.3。 某处在Servlet.service方法或在你的web应用的任何地方(你应该能够获得参考ServletContext几乎从任何地方的webapp):

Callable<ResultOfMyTask> callable = new Callable<ResultOfMyTask>() {
    public ResultOfMyTask call() {
        // here goes your task code which is to be invoked by thread pool 
    }
};

final ServletContext servletContext = ...;
final ExecutorService threadPool = (ExecutorService) servletContext.getAttribute("threadPoolAlias");
final Future<ResultOfMyTask> myTask = threadPool.submit(callable);;

你应该参考存储myTask,可以从其他线程调用它来发现它是否完成,结果是什么。

希望这可以帮助...



Answer 2:

对于你的使用情况,您可以利用Timer和TimerTask在Java平台可用来定期执行后台任务。

import java.util.Timer;
import java.util.TimerTask;

TimerTask dbTask = new TimerTask() {
    @Override
    public void run() {
        // Perform Db call and do some action
    }
};

final long INTERVAL = 1000 * 60 * 5; // five minute interval

// Run the task at fixed interval
new Timer(true).scheduleAtFixedRate(dbTask, 0, INTERVAL);

请注意,如果任务需要超过五分钟才能完成,后续任务将不会被并行执行。 相反,他们会在队列中等待,将在前面的一个完成之后另一个迅速执行一个。

您可以在一个单独的类包装这个代码,并从启动的servlet调用。

一般情况下,它是一个很好的做法,执行这些类型的周期性后台作业的Servlet容器之外,他们应得到有效利用服务的HTTP请求。



Answer 3:

对于一个简单的背景任务,你不需要任何种类的线程池都没有。 所有你需要做的是:

  1. 启动一个线程
  2. 检查是否后台进程应停止
  3. 有它轮询数据库
  4. 存放新鲜调查数据访问的地方
  5. 检查是否后台进程应停止
  6. 去睡觉
  7. 重复步骤#2-#7

ServletContextListener即启动一个线程来执行,你在实现一个类定义上述步骤Runnable 。 在contextDestroyed方法,设置触发#2和#5以上指出的检查的标志,然后调用Thread.interrupt所以你的线程终止。

你的后台任务绝对不应该试图同步发送邮件给客户。 取而代之的是,通知等待使用一些其他的机制,像轮询Object.notify显示器上(这并不真正使任何意义,因为你不希望阻止客户检查当前状态),更新一些类型的时间戳,或者只是有轮询的客户端检查#4提供的最新数据。



文章来源: tomcat 6 thread pool for asynchronous processing