Play框架的continuations如何控制http线程?

7
我们在 Web 应用程序中实现了一个功能,通过使用 Play 的 Continuations 像聊天应用程序一样,根据服务器上的新事件更新 GUI。在生产环境中运行了一段时间后,我们开始遇到服务器挂起的情况,更具体地说,我们的 Glassfish 服务器的 http 连接器停止接受新请求。线程转储向我们显示,http 线程池中的所有 http 线程都在等待调用 Play Promises。我们的线程池有 5 个线程(默认值),这意味着有 5 个客户端正在等待被通知,并且除非一些实际客户端关闭其连接,否则服务器无法接受更多的 http 连接。
根据 Play 文档对 Continuations/Request Suspension 的描述,当通过调用 await() 暂停一个请求时,该请求的线程应该被释放。但是这里发生的情况并不是这样。
参考:http://www.playframework.org/documentation/1.2.3/asynchronous 我研究了 Play 的源代码,但没有找到任何提示。我的代码似乎也没问题,但我不确定(请参见下文)。我希望有人可以指出我可能做错了什么。
版本信息:
Play 1.2.3
Glassfish 3.1.1

源代码:
public class Sessions extends Controller {
        public static void waitFor(Query query, long lastSessionId, List<Long> openSessionIds) {
                String clientId = request.remoteAddress;

                List<Session> sessions = query
                        .with(new UpdatedSessions(lastSessionId, openSessionIds))
                        .execute();

                Logger.info("%s -> Updated sessions since %s + %s: %s", clientId, lastSessionId, openSessionIds, sessions);

                while(sessions.isEmpty()) {
                        List<Long> ids = await(MailBox.watch(query, clientId));
                        Logger.info("%s -> Received ids: %s", clientId, ids);

                        sessions = query.with(new SessionIds(ids)).execute();
                        Logger.info("%s -> Queried sessions: %s", clientId, sessions);
                }

                Logger.info("%s -> Delivering %s", clientId, sessions);
                List<Tile> tiles = Tile.forGates(query.gates());
                render(sessions, tiles);
        }
}

public class MailBox {
        private static List<Promise<List<Long>>> promises = Collections.synchronizedList(new ArrayList<Promise<List<Long>>>());

        public static Future<List<Long>> watch(Query query, String clientId) {
                Logger.info("Mailbox.watch(%s, %s)", query, clientId);
                Promise<List<Long>> promise = new Promise<List<Long>>();
                promises.add(promise);
                return promise;
        }

        public static void put(final long sessionId) {
                Logger.info("Mailbox.put(%s): promises=%s", sessionId, promises);

                if(promises.isEmpty())
                        return;

                final List<Promise<List<Long>>> targets = seizePromises();

                new Thread() {
                        @Override
                        public void run() {
                                // It's a list because we will accumulate ids before notifying the waiting clients
                                List<Long> ids = Arrays.asList(sessionId);

                                Logger.info("Mailbox.put(%s): target=%s", sessionId, targets);
                                for(Promise<List<Long>> promise : targets)
                                        promise.invoke(ids);
                        }
                }.start();
        }

        private static List<Promise<List<Long>>> seizePromises() {
                List<Promise<List<Long>>> result = new ArrayList<Promise<List<Long>>>();
                synchronized (promises) {
                        result.addAll(promises);
                        promises.clear();
                }
                return result;
        }
}

线程转储(已削减,请查看完整转储http://pastebin.com/1TdV1njv):

2011-11-22 10:42:00
Full thread dump OpenJDK 64-Bit Server VM (20.0-b11 mixed mode):

"RMI TCP Connection(idle)" daemon prio=10 tid=0x0000000000ffe000 nid=0xca0 waiting on condition [0x00007f5cf1fa4000]
   java.lang.Thread.State: TIMED_WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000000e27f9300> (a java.util.concurrent.SynchronousQueue$TransferStack)
    at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:226)
    at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:453)
    at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:352)
    at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:903)
    at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1043)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1103)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:679)

   Locked ownable synchronizers:
    - None

"JMX server connection timeout 87" daemon prio=10 tid=0x00000000012d6000 nid=0xc9e in Object.wait() [0x00007f5cebefd000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000000fe5242d8> (a [I)
    at com.sun.jmx.remote.internal.ServerCommunicatorAdmin$Timeout.run(ServerCommunicatorAdmin.java:168)
    - locked <0x00000000fe5242d8> (a [I)
    at java.lang.Thread.run(Thread.java:679)

   Locked ownable synchronizers:
    - None

"RMI TCP Connection(3)-127.0.0.1" daemon prio=10 tid=0x0000000001374000 nid=0xc9c runnable [0x00007f5cf20a5000]
   java.lang.Thread.State: RUNNABLE
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.read(SocketInputStream.java:146)
    at java.io.BufferedInputStream.fill(BufferedInputStream.java:235)
    at java.io.BufferedInputStream.read(BufferedInputStream.java:254)
    - locked <0x00000000fe5a2010> (a java.io.BufferedInputStream)
    at java.io.FilterInputStream.read(FilterInputStream.java:83)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:808)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:667)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:679)

   Locked ownable synchronizers:
    - <0x00000000fe521bc8> (a java.util.concurrent.ThreadPoolExecutor$Worker)

"RMI TCP Accept-0" daemon prio=10 tid=0x0000000001375000 nid=0xc99 runnable [0x00007f5ceb3f2000]
   java.lang.Thread.State: RUNNABLE
    at java.net.PlainSocketImpl.socketAccept(Native Method)
    at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:375)
    at java.net.ServerSocket.implAccept(ServerSocket.java:470)
    at java.net.ServerSocket.accept(ServerSocket.java:438)
    at sun.management.jmxremote.LocalRMIServerSocketFactory$1.accept(LocalRMIServerSocketFactory.java:52)
    at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.executeAcceptLoop(TCPTransport.java:387)
    at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.run(TCPTransport.java:359)
    at java.lang.Thread.run(Thread.java:679)

   Locked ownable synchronizers:
    - None

"Attach Listener" daemon prio=10 tid=0x0000000001341800 nid=0xc98 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"http-thread-pool-8080(5)" daemon prio=10 tid=0x00007f5cec119800 nid=0xbb5 waiting on condition [0x00007f5cea8e6000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000000fe4d6bb8> (a java.util.concurrent.CountDownLatch$Sync)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:838)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:998)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1304)
    at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:235)
    at play.libs.F$Promise.get(F.java:46)
    at play.Invoker.invokeInThread(Invoker.java:73)
    at play.server.ServletWrapper.service(ServletWrapper.java:130)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1539)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
    at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:330)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:174)
    at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:828)
    at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:725)
    at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1019)
    at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
    at java.lang.Thread.run(Thread.java:679)

   Locked ownable synchronizers:
    - <0x00000000e39f4eb0> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)

"http-thread-pool-8080(4)" daemon prio=10 tid=0x00007f5cec142800 nid=0xbb4 waiting on condition [0x00007f5cea9e7000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000000f6ff9e90> (a java.util.concurrent.CountDownLatch$Sync)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:838)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:998)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1304)
    at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:235)
    at play.libs.F$Promise.get(F.java:46)
    at play.Invoker.invokeInThread(Invoker.java:73)
    at play.server.ServletWrapper.service(ServletWrapper.java:130)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1539)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
    at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:330)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:174)
    at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:828)
    at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:725)
    at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1019)
    at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
    at java.lang.Thread.run(Thread.java:679)

   Locked ownable synchronizers:
    - <0x00000000fe4a3b90> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)

"http-thread-pool-8080(3)" daemon prio=10 tid=0x00007f5cec140800 nid=0xbb3 waiting on condition [0x00007f5ceaae8000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000000fe4a3288> (a java.util.concurrent.CountDownLatch$Sync)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:838)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:998)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1304)
    at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:235)
    at play.libs.F$Promise.get(F.java:46)
    at play.Invoker.invokeInThread(Invoker.java:73)
    at play.server.ServletWrapper.service(ServletWrapper.java:130)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1539)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
    at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:330)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:174)
    at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:828)
    at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:725)
    at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1019)
    at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
    at java.lang.Thread.run(Thread.java:679)

   Locked ownable synchronizers:
    - <0x00000000e28c0fd0> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)

"http-thread-pool-8080(2)" daemon prio=10 tid=0x00007f5cec02d000 nid=0xbb2 waiting on condition [0x00007f5ceabe9000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000000f72411d8> (a java.util.concurrent.CountDownLatch$Sync)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:838)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:998)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1304)
    at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:235)
    at play.libs.F$Promise.get(F.java:46)
    at play.Invoker.invokeInThread(Invoker.java:73)
    at play.server.ServletWrapper.service(ServletWrapper.java:130)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1539)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
    at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:330)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:174)
    at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:828)
    at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:725)
    at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1019)
    at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
    at java.lang.Thread.run(Thread.java:679)

   Locked ownable synchronizers:
    - <0x00000000f63b3958> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)

"http-thread-pool-8080(1)" daemon prio=10 tid=0x00007f5cec02c800 nid=0xbb1 waiting on condition [0x00007f5ceb0ee000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000000f7424bd0> (a java.util.concurrent.CountDownLatch$Sync)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:838)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:998)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1304)
    at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:235)
    at play.libs.F$Promise.get(F.java:46)
    at play.Invoker.invokeInThread(Invoker.java:73)
    at play.server.ServletWrapper.service(ServletWrapper.java:130)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1539)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
    at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:330)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:174)
    at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:828)
    at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:725)
    at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1019)
    at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
    at java.lang.Thread.run(Thread.java:679)

   Locked ownable synchronizers:
    - <0x00000000f63c78b0> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)

"SCR Component Actor" daemon prio=10 tid=0x00007f5ce472d000 nid=0xba8 in Object.wait() [0x00007f5ceadec000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000000e260c920> (a java.util.LinkedList)
    at java.lang.Object.wait(Object.java:502)
    at org.apache.felix.scr.impl.ComponentActorThread.run(ComponentActorThread.java:74)
    - locked <0x00000000e260c920> (a java.util.LinkedList)
    at java.lang.Thread.run(Thread.java:679)

   Locked ownable synchronizers:
    - None

"pool-7-thread-1" prio=10 tid=0x00007f5ce5134800 nid=0xba7 waiting on condition [0x00007f5ceaceb000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000000e260cb78> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
    at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:386)
    at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1043)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1103)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:679)

   Locked ownable synchronizers:
    - None

1
好奇一下,如果直接从Play运行生产模式(而不是使用Glassfish Web容器),您是否会遇到相同的问题? - Scott A Miller
不,play run 生产模式下不会发生这种情况。没有 NIO 线程在 Promise 的倒计时门闩上等待。我曾在 Play 的 Google 讨论组上提出了同样的问题,并得到 Guillaume Bort 的回复,他说 Play 的异步特性仅适用于 Netty 服务器(Play runner 使用 Netty)。 - Célio
谢谢 - 你能回答这个问题并接受它吗?这也应该放在Play框架网站的部署文档中。在我看来,这是必要的信息! - Scott A Miller
当然,我只是在最后做一些研究,以免失去希望,然后我会写一个答案。我同意你的观点,文档中绝对没有提到这一点,这非常具有误导性。 - Célio
1个回答

5
正如Guillaume在Google Group网站上提到的那样,这是因为Play continuations只适用于内置的Netty服务器。你完全正确,文档中缺乏这方面的信息,但事实上只有在使用Netty时,Play才能控制请求线程。对于所有其他服务器,Play需要创建一个包装器来包装servlet API,这意味着Play无法保持线程。

不幸的是,当使用部署到非首选平台的Play时,这是其中之一的权衡。


并行讨论:http://groups.google.com/group/play-framework/browse_thread/thread/8eedf7fa45772945/ - Célio

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接