java Tomcat 7 上的 Servlet 3 异步任务

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7960916/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 22:13:02  来源:igfitidea点击:

Servlet 3 Async task on Tomcat 7

javajakarta-eeservletscomettomcat7

提问by danny.lesnik

I'm trying to implement Simple chat using Servlet 3.0 and Comet pattern based on its async support.

我正在尝试使用 Servlet 3.0 和 Comet 模式基于其异步支持来实现简单聊天。

I'm inspired by this article: http://www.javaworld.com/javaworld/jw-02-2009/jw-02-servlet3.html?page=3

我受到这篇文章的启发:http: //www.javaworld.com/javaworld/jw-02-2009/jw-02-servlet3.html?page=3

My servlet looks like this.

我的 servlet 看起来像这样。

@WebServlet(name="chatServlet", urlPatterns={"/ChatServlet"}, asyncSupported=true)
public class ChatServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         AsyncContext aCtx = request.startAsync(request, response); 
         ServletContext appScope = request.getServletContext();    
         List<AsyncContext> watchers = (List<AsyncContext>) appScope.getAttribute("watchers");
         watchers.add(aCtx); //register the watcher
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
          AsyncContext aCtx = request.startAsync(request, response); 
          ServletContext appScope = request.getServletContext(); 
          Queue<String> messages = (Queue<String>)appScope.getAttribute("messages");
          messages.add(someMessage);
    }
} 

now my Listener looks like this:

现在我的监听器看起来像这样:

@WebListener
public class ChatPushService implements ServletContextListener {

        @Override
        public void contextInitialized(ServletContextEvent sce) {
              final List<AsyncContext> watchers = new  ArrayList<AsyncContext>();
             sce.getServletContext().setAttribute("watchers", watchers);
              // store new messages not published yet
             Queue<String> messages = new ConcurrentLinkedQueue<String>();
             sce.getServletContext().setAttribute("messages", messages);
             Executor messageExecutor = Executors.newCachedThreadPool(); 
             final Executor watcherExecutor = Executors.newCachedThreadPool();
             while(true)
              {      

                 if(!messages.isEmpty()) 
                 {
                     System.out.println("notEmpty");
                    String message =  messages.poll(); 
                    messageExecutor.execute(new Runnable(){

                        @Override
                        public void run() {
                             for(final AsyncContext aCtx : watchers){
                                 watcherExecutor.execute(new Runnable(){

                                     @Override
                                        public void run() {
                                           try {
                                            aCtx.getResponse().getWriter().print("brrrrr");
                                        } catch (IOException e) {
                                            // TODO Auto-generated catch block
                                            e.printStackTrace();
                                        }
                                     }
                                 });
                             }
                        }
                 });
              }
        }

    }
    }

When I'm starting my it's freezing during container initiation.

当我开始时,它在容器启动期间冻结。

Nov 1, 2011 1:12:09 AM org.apache.catalina.core.AprLifecycleListener init
INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: /usr/lib/jvm/java-6-openjdk/jre/lib/amd64/server:/usr/lib/jvm/java-6-openjdk/jre/lib/amd64:/usr/lib/jvm/java-6-openjdk/jre/../lib/amd64:/usr/java/packages/lib/amd64:/usr/lib/jni:/lib:/usr/lib
Nov 1, 2011 1:12:09 AM org.apache.tomcat.util.digester.SetPropertiesRule begin
WARNING: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 'org.eclipse.jst.jee.server:Servlet3Comet' did not find a matching property.
Nov 1, 2011 1:12:09 AM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-bio-8080"]
Nov 1, 2011 1:12:09 AM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["ajp-bio-8009"]
Nov 1, 2011 1:12:09 AM org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 624 ms
Nov 1, 2011 1:12:09 AM org.apache.catalina.core.StandardService startInternal
INFO: Starting service Catalina
Nov 1, 2011 1:12:09 AM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/7.0.22

It looks like public void contextInitializedfunction is not running asynchronously on background and is blocking further container initialization.

看起来public void contextInitialized函数没有在后台异步运行,并且正在阻止进一步的容器初始化。

Why?

为什么?

can anybody help me on this issue?

有人可以帮我解决这个问题吗?

采纳答案by Ramesh PVK

You are running while loop inside contextInitialized()method which is wrong. contextInitialized()is invoked by Servlet Container as part of the application startup, having while loop there will block your app start.

您正在contextInitialized()方法中运行 while 循环 ,这是错误的。 contextInitialized()由 Servlet Container 作为应用程序启动的一部分调用,在那里使用 while 循环会阻止您的应用程序启动。

Modified the code such the ContextListener will start one daemon thread which publishes the messages to the watchers

修改了代码,这样 ContextListener 将启动一个守护线程,该线程将消息发布给观察者

@WebListener
public class ChatPushService implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
          final List<AsyncContext> watchers = new  ArrayList<AsyncContext>();
         sce.getServletContext().setAttribute("watchers", watchers);
          // store new messages not published yet
         Queue<String> messages = new ConcurrentLinkedQueue<String>();
         sce.getServletContext().setAttribute("messages", messages);
         new chatManager(sce.getServletContext()).start(); //START DAEMON

      }
}
public class ChatManager implements Runnable
{
ServletContext servletCtx;
public ChatManager(ServletContext ctx)
{
     this.servletCtx = ctx;
}
public void run()
{
         List<AsyncContext> watchers = (List<AsyncContext>) servletCtx.getAttribute("watchers");
     Queue<String> messages = (Queue<String>)appScope.getAttribute("messages");
     Executor messageExecutor = Executors.newCachedThreadPool(); 
         final Executor watcherExecutor = Executors.newCachedThreadPool();
         while(true)
          {      

             if(!messages.isEmpty()) 
             {
                 System.out.println("notEmpty");
                String message =  messages.poll(); 
                messageExecutor.execute(new Runnable(){

                    @Override
                    public void run() {
                         for(final AsyncContext aCtx : watchers){
                             watcherExecutor.execute(new Runnable(){

                                 @Override
                                    public void run() {
                                       try {
                                        aCtx.getResponse().getWriter().print("brrrrr");
                                    } catch (IOException e) {
                                        // TODO Auto-generated catch block
                                        e.printStackTrace();
                                    }
                                 }
                             });
                         }
                    }
             });
          }
    }

}

}

回答by gbenroscience

I can't comment on Ramesh's code, so I have to place it here... Since no thread wraps round the ChatManager runnable, I believe you should call run() on it and not start(). Also, quite obvious though, it should be new ChatManager()..not new chatManager()...account of Java been case-sensitive.

我无法评论 Ramesh 的代码,所以我必须把它放在这里...因为没有线程环绕 ChatManager runnable,我相信你应该在它上面调用 run() 而不是 start()。另外,很明显,它应该是 new ChatManager()..not new chatManager() ... Java 帐户区分大小写。