嵌入式Jetty服务器挂起

时间:2012-10-05 06:31:36

标签: java servlets jetty deadlock

我正在尝试在我的程序中嵌入一个jetty服务器,它似乎在每个线程获得服务器一个请求后挂起。我写的测试用例代码是:

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.servlet.Context;
import org.mortbay.jetty.servlet.ServletHolder;
import org.mortbay.thread.QueuedThreadPool;

public class EmbeddedJetty
{
    public static void initServer(int port) throws Exception
    {
        final AtomicLong counter = new AtomicLong();
        final Server server = new Server(port);
        server.setThreadPool(new QueuedThreadPool(3));
        Context context = new Context(server, "/", Context.SESSIONS);
        context.addServlet(new ServletHolder(new HttpServlet()
        {
            @Override
            protected void doGet(HttpServletRequest req, 
                                 HttpServletResponse resp) 
                throws ServletException, IOException
            {
                PrintWriter writer = resp.getWriter();
                String msg = "Served page #" + counter.incrementAndGet() + 
                        " at " + new Date();
                writer.print(msg);
                writer.close();
                System.out.println("[Server] " + msg);

            }
        }), "/*");
        server.start();
        System.out.println("[Server] Started Jetty server");
    }

    public static void initClient(final int port)
    {
        new Thread()
        {
            public void run()
            {
                String urlString = "http://localhost:" + port + "/myBT";
                while (true)
                {
                    try
                    {
                        System.out.println("[Client] Sending request to " + 
                                 urlString);
                        HttpClient httpclient = new DefaultHttpClient();
                        HttpGet httpget = new HttpGet(urlString);
                        HttpResponse response = httpclient.execute(httpget);
                        StatusLine statusLine = response.getStatusLine();

                        System.out.println("[Client] Got response [" +
                                response.getProtocolVersion() + "] [" +
                                statusLine.getStatusCode() + "] [" +
                                statusLine.getReasonPhrase() + "]");
                        HttpEntity entity = response.getEntity();
                        if (entity != null)
                        {
                            entity.consumeContent();
                        }
                    }
                    catch (Exception ex)
                    {
                        ex.printStackTrace();
                    }
                }
            }
        }.start();
    }

    public static void main(String[] args) throws Exception
    {
        int port = 8090;
        initServer(port);
        initClient(port);
    }
}

该程序的输出是:

$ java -cp build/libs/sqlcache.jar EmbeddedJetty
2012-10-04 23:24:30.797:INFO::Logging to STDERR via org.mortbay.log.StdErrLog
2012-10-04 23:24:30.842:INFO::jetty-6.1.x
2012-10-04 23:24:30.945:INFO::Started SocketConnector@0.0.0.0:8090
[Server] Started Jetty server
[Client] Sending request to http://localhost:8090/myBT
[Server] Served page #1 at Thu Oct 04 23:24:31 PDT 2012
[Client] Got response [HTTP/1.1] [200] [OK]
[Client] Sending request to http://localhost:8090/myBT
[Server] Served page #2 at Thu Oct 04 23:24:31 PDT 2012
[Client] Got response [HTTP/1.1] [200] [OK]
[Client] Sending request to http://localhost:8090/myBT

然后它就会挂起。

线程转储如下所示:

Full thread dump Java HotSpot(TM) 64-Bit Server VM (20.10-b01-428 mixed mode):

"454514340@qtp-703447155-2" prio=5 tid=1029f2000 nid=0x10aa38000 runnable [10aa37000]
   java.lang.Thread.State: RUNNABLE
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.read(SocketInputStream.java:129)
    at org.mortbay.io.ByteArrayBuffer.readFrom(ByteArrayBuffer.java:382)
    at org.mortbay.io.bio.StreamEndPoint.fill(StreamEndPoint.java:114)
    at org.mortbay.jetty.bio.SocketConnector$Connection.fill(SocketConnector.java:198)
    at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:290)
    at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
    at org.mortbay.jetty.bio.SocketConnector$Connection.run(SocketConnector.java:228)
    at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)

"DestroyJavaVM" prio=5 tid=102928000 nid=0x100501000 waiting on condition [00000000]
   java.lang.Thread.State: RUNNABLE

"Thread-5" prio=5 tid=1029d5800 nid=0x10a935000 runnable [10a934000]
   java.lang.Thread.State: RUNNABLE
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.read(SocketInputStream.java:129)
    at org.apache.http.impl.io.AbstractSessionInputBuffer.fillBuffer(AbstractSessionInputBuffer.java:130)
    at org.apache.http.impl.io.SocketInputBuffer.fillBuffer(SocketInputBuffer.java:127)
    at org.apache.http.impl.io.AbstractSessionInputBuffer.readLine(AbstractSessionInputBuffer.java:233)
    at org.apache.http.impl.conn.DefaultResponseParser.parseHead(DefaultResponseParser.java:98)
    at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:210)
    at org.apache.http.impl.AbstractHttpClientConnection.receiveResponseHeader(AbstractHttpClientConnection.java:271)
    at org.apache.http.impl.conn.DefaultClientConnection.receiveResponseHeader(DefaultClientConnection.java:233)
    at org.apache.http.impl.conn.AbstractClientConnAdapter.receiveResponseHeader(AbstractClientConnAdapter.java:209)
    at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:292)
    at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:126)
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:483)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:641)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:576)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:554)
    at EmbeddedJetty$2.run(EmbeddedJetty.java:67)

"Timer-0" daemon prio=5 tid=101b8f800 nid=0x10a820000 in Object.wait() [10a81f000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <7f42b20d0> (a java.util.TaskQueue)
    at java.util.TimerThread.mainLoop(Timer.java:509)
    - locked <7f42b20d0> (a java.util.TaskQueue)
    at java.util.TimerThread.run(Timer.java:462)

"Poller SunPKCS11-Darwin" daemon prio=1 tid=10286e800 nid=0x10a71d000 waiting on condition [10a71c000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep(Native Method)
    at sun.security.pkcs11.SunPKCS11$TokenPoller.run(SunPKCS11.java:692)
    at java.lang.Thread.run(Thread.java:680)

"1753620260@qtp-703447155-1 - Acceptor0 SocketConnector@0.0.0.0:8090" prio=5 tid=1019af800 nid=0x10a5ec000 runnable [10a5eb000]
   java.lang.Thread.State: RUNNABLE
    at java.net.PlainSocketImpl.socketAccept(Native Method)
    at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:408)
    - locked <7f42b2238> (a java.net.SocksSocketImpl)
    at java.net.ServerSocket.implAccept(ServerSocket.java:462)
    at java.net.ServerSocket.accept(ServerSocket.java:430)
    at org.mortbay.jetty.bio.SocketConnector.accept(SocketConnector.java:99)
    at org.mortbay.jetty.AbstractConnector$Acceptor.run(AbstractConnector.java:708)
    at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)

"1169804875@qtp-703447155-0" prio=5 tid=101a12000 nid=0x10a4e9000 runnable [10a4e8000]
   java.lang.Thread.State: RUNNABLE
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.read(SocketInputStream.java:129)
    at org.mortbay.io.ByteArrayBuffer.readFrom(ByteArrayBuffer.java:382)
    at org.mortbay.io.bio.StreamEndPoint.fill(StreamEndPoint.java:114)
    at org.mortbay.jetty.bio.SocketConnector$Connection.fill(SocketConnector.java:198)
    at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:290)
    at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
    at org.mortbay.jetty.bio.SocketConnector$Connection.run(SocketConnector.java:228)
    at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)

"Low Memory Detector" daemon prio=5 tid=1018a8000 nid=0x10a013000 runnable [00000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" daemon prio=9 tid=1018a7000 nid=0x109f10000 waiting on condition [00000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" daemon prio=9 tid=1018a6800 nid=0x109e0d000 waiting on condition [00000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" daemon prio=9 tid=1018a5800 nid=0x109d0a000 waiting on condition [00000000]
   java.lang.Thread.State: RUNNABLE

"Surrogate Locker Thread (Concurrent GC)" daemon prio=5 tid=1018a4800 nid=0x109c07000 waiting on condition [00000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" daemon prio=8 tid=10189c000 nid=0x1098ea000 in Object.wait() [1098e9000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <7f42c92e0> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
    - locked <7f42c92e0> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)

"Reference Handler" daemon prio=10 tid=10189b000 nid=0x1097e7000 in Object.wait() [1097e6000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <7f42b02a8> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:485)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
    - locked <7f42b02a8> (a java.lang.ref.Reference$Lock)

"VM Thread" prio=9 tid=101896800 nid=0x1096e4000 runnable 

"Gang worker#0 (Parallel GC Threads)" prio=9 tid=101802800 nid=0x102201000 runnable 

"Gang worker#1 (Parallel GC Threads)" prio=9 tid=101803000 nid=0x102304000 runnable 

"Concurrent Mark-Sweep GC Thread" prio=9 tid=10184d800 nid=0x1093f0000 runnable 
"VM Periodic Task Thread" prio=10 tid=1018b9800 nid=0x10a116000 waiting on condition 

"Exception Catcher Thread" prio=10 tid=101801800 nid=0x1017fa000 runnable 
JNI global references: 1726

Heap
 par new generation   total 19136K, used 3756K [7f3000000, 7f44c0000, 7f44c0000)
  eden space 17024K,   9% used [7f3000000, 7f319b348, 7f40a0000)
  from space 2112K, 100% used [7f42b0000, 7f44c0000, 7f44c0000)
  to   space 2112K,   0% used [7f40a0000, 7f40a0000, 7f42b0000)
 concurrent mark-sweep generation total 63872K, used 350K [7f44c0000, 7f8320000, 7fae00000)
 concurrent-mark-sweep perm gen total 21248K, used 9994K [7fae00000, 7fc2c0000, 800000000)

我正在使用Jetty 6.1.26

导致服务器挂起的原因是什么?

编辑:添加超时,例如:

    SocketConnector connector = new SocketConnector();
    connector.setMaxIdleTime(1000);
    connector.setSoLingerTime(-1);
    connector.setPort(port);
    server.setConnectors(new Connector[] { connector });

似乎解决了这个问题,但我想首先了解出了什么问题。

1 个答案:

答案 0 :(得分:1)

一方面:您不需要新的HttpClient,您可以重复使用它。我怀疑你的麻烦是底层连接没有关闭/释放(参见"Thread-5" prio=5 tid=1029d5800 nid=0x10a935000 runnable [10a934000]

干杯,