Java(Tomcat 8)Web服务器响应HTTP请求生成线程是否安全?我看到有人在帖子和论坛上说这绝对不错,而另一些人则说不行。
我的用例将是这样的:
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 }
当我说“安全”时,我的意思是关于网络服务器稳定性的建议有天生的危险。正如@Burrman指出的那样,在这里线程池是个好主意,我将这样做。如果我正在使用线程池,那么我应该关注或需要解决的servlet容器是否还有其他潜在问题?
我想我正在考虑的是例如JDBC连接。我相信建议使用JNDI资源等进行设置,并使用Tomcat config进行配置。像我的示例中那样,是否有必要或建议使用类似的方法来生成任意线程?
首先,看起来您正在修改result两个线程中的对象。这不是线程安全的,因为first和second线程之间的操作可能彼此之间或运行servlet的线程之间不可见。有关更多信息,请参见本文。
result
first
second
其次,如果您正在其他线程中修改响应,则不会,这将是不安全的。退出doGet方法后,应考虑发送的响应。在您的示例中,有可能在这两个线程运行之前将响应发送回客户端。
doGet
假设MyResult result影响了response对象(您将添加result到中response,它正在影响响应代码,等等)。有几种方法可以解决此问题。
MyResult result
response
使用ExecutorService和Future:
ExecutorService
Future
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 f1 = executor.submit(new Callable() { @Override public Result1 call() throws Exception { // do expensive stuff here. return result; } });
Future f2 = executor.submit(new Callable() { @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 }
一种更高级的技术是异步处理。如果您的请求需要很长时间才能处理,则使用异步处理是一个好主意。它不会提高任何一个请求的延迟,但是它确实允许Tomcat在任何给定时间点处理更多请求。
一个简单的例子是:
@WebServlet(urlPatterns={"/asyncservlet"}, asyncSupported=true) // Rather than @WebServlet, you can also specify these parameters in web.xml public class AsyncServlet extends HttpServlet { @Override public void doGet(HttpServletRequest request, HttpServletResponse response) { response.setContentType("text/html;charset=UTF-8"); final AsyncContext acontext = request.startAsync(); acontext.start(new Runnable() { public void run() { // perform time consuming steps here. acontext.complete(); } }