我的Java(Tomcat 8)Web服务器是否可以安全地生成线程以响应HTTP请求?我看到帖子和论坛有些人说absolutely fine,其他人说not to do it。
我的用例是这样的:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
...
...
final MyResult res = new MyResult();
Thread first = new Thread(new Runnable() {
@Override
public void run() {
// put this into res
}
});
Thread second = new Thread(new Runnable() {
@Override
public void run() {
// put that into res
}
});
first.start();
second.start();
first.join(10000);
second.join(10000);
// return res
}
当我说安全时,我的意思是关于Web服务器的稳定性,我提出的内容是否有任何本质上的危险。正如@Burrman指出的那样,线程池在这里是个好主意,我会这样做。如果我正在使用线程池,那么我应该关注或需要解决的servlet容器是否存在任何其他潜在问题?
我想我正在考虑的是,例如,JDBC连接。我相信建议使用JNDI资源等进行设置,并使用Tomcat配置进行配置。是否有必要或建议产生任意线程,如我的例子?
答案 0 :(得分:6)
首先,它看起来你正在修改两个线程中的$args = array(
'post_type' => array( 'videos' ),
'orderby' => 'rand',
'posts_per_page' => 5,
'meta_query' => array(
array(
'key' => 'post_title',
'value' => 'YouTube.com',
'compare' => 'IN',
)
)
);
对象。这不是线程安全的,因为result
和first
线程可能彼此不可见或者servlet正在运行的线程可见。有关详细信息,请参阅this article。
其次,如果你在这些其他线程中修改响应,不,这将是不安全的。退出second
方法后,您应该考虑发送的响应。在您的示例中,在这两个线程运行之前,响应将有可能被发送回客户端。
假设doGet
影响MyResult result
对象(您要将response
添加到result
,它会影响响应代码,等等)。有几种方法可以解决这个问题。
使用response
和ExecutorService
:
Future
更先进的技术是Asynchronous Processing。如果您的请求需要很长时间来处理,则使用异步处理是一个好主意。它不会改善任何一个请求的延迟,但它确实允许Tomcat在任何给定的时间点处理更多请求。
一个简单的例子是:
public void doGet(HttpServletRequest request, HttpServletResponse response) {
// Creating a new ExecutorService for illustrative purposes.
// As mentioned in comments, it is better to create a global
// instance of ExecutorService and use it in all servlets.
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<Result1> f1 = executor.submit(new Callable<Result1>() {
@Override
public Result1 call() throws Exception {
// do expensive stuff here.
return result;
}
});
Future<Result2> f2 = executor.submit(new Callable<Result2>() {
@Override
public Result2 call() throws Exception {
// do expensive stuff here.
return result;
}
});
// shutdown allows the executor to clean up its threads.
// Also prevents more Callables/Runnables from being submitted.
executor.shutdown();
// The call to .get() will block until the executor has
// completed executing the Callable.
Result1 r1 = f1.get();
Result2 r2 = f2.get();
MyResult result = new MyResult();
// add r1 and r2 to result.
// modify response based on result
}
答案 1 :(得分:3)
另外,除了A
的优秀答案之外,我真的建议你考虑一下你的结果计算是否可以用 map / filter / group operations 来表达在列表或地图上,因为在90%的情况下,它可以这样做。
如果情况确实如此,我建议您使用this official tutorial
中概述的 Java 8kuporific
功能
如果您有兴趣是否/如何以这种方式表达您的计算,请提出单独的问题
另外,回答你的初始问题 - 在任何地方(包括servlet)生成线程来并行计算都非常好,但我真的建议测量性能之前和之后优化后主要是因为in this superb article
所述的原因答案 2 :(得分:0)
原则上,是的。但是你必须密切关注你产生的线程总数,以确保你没有使用太多的资源。
使用线程池可以帮助控制线程数。
答案 3 :(得分:0)
在我看来
要明确:这不是执行典型的日常AJAX任务的常规方法(必须将设计划分为“主要”请求和下一个孩子ajax请求,使用您的框架),但AJAX可以呈现后台长线程的状态。
在我的构思中,线程或等价物可以从少数/罕见的请求开始,远远低于限制等,但如果是从每个请求完成,那么设计是非常糟糕的。
答案 4 :(得分:-1)
JEE服务器在线程局部变量中存储一些信息。例如。 JAAS的安全上下文,JTA事务,...新的普通java线程无法访问此类信息。 AsyncContext
和JEE ExecuterService
已集成到服务器中,可以将请求状态透明地传播到托管线程。