views:

53

answers:

3

I have developed a simple server using Tomcat which runs a servlet.

The servlet calls a command line program - which takes about 20 seconds to execute then returns the result to the user via JSON. The problem is - if i make above 2 simultaneous requests, the servlet blocks until one of the previous requests is completed.

An example of this can be seen below - "Im in" is the top of the servlet, and the list of results is after the servlet is executed. All requests were made at the same time - but you can clearly see they are not dealt with simultaneously. What setting do I need to change in tomcat in order to have all requests handeled at the same time?

Im in 

Im in 

FVFNT01 STOP_IDLE FVFNT03 STOP_IDLE FVFNT16 STOP_IDLE FVFNT17 STOP_IDLE
FVFNT01 STOP_IDLE FVFNT03 STOP_IDLE FVFNT16 STOP_IDLE FVFNT17 STOP_IDLE
Im in

FVFNT01 STOP_IDLE FVFNT03 STOP_IDLE FVFNT16 STOP_IDLE FVFNT17 STOP_IDLE
Im in

FVFNT01 STOP_IDLE FVFNT03 STOP_IDLE FVFNT16 STOP_IDLE FVFNT17 STOP_IDLE
Im in

FVFNT01 STOP_IDLE FVFNT03 STOP_IDLE FVFNT16 STOP_IDLE FVFNT17 STOP_IDLE
Im in

FVFNT01 STOP_IDLE FVFNT03 STOP_IDLE FVFNT16 STOP_IDLE FVFNT17 STOP_IDLE
Im in

FVFNT01 STOP_IDLE FVFNT03 STOP_IDLE FVFNT16 STOP_IDLE FVFNT17 STOP_IDLE
Im in

FVFNT01 STOP_IDLE FVFNT03 STOP_IDLE FVFNT16 STOP_IDLE FVFNT17 STOP_IDLE
A: 

Requests to servlets are handled concurrently by default. There is no setting that enables/disables this behaviour. This is confirmed by the JavaDoc for HttpServlet:

Servlets typically run on multithreaded servers, so be aware that a servlet must handle concurrent requests and be careful to synchronize access to shared resources.

However, if your servlet implements the marker interface SingleThreadModel, the servlet will only handle one request at-a-time. However, use of this interface is generally considered a bad practice, and because you didn't mention it, I assume you're not using it.

Of course even if you're not implementing SingleThreadModel you can make any servlet single-threaded using (probably inappropriate) synchronisation, e.g.

class MyServlet extends HttpServlet {

  private void Object sharedObject = new Object()

  protected synchronized void doGet(HttpServletRequest req, HttpServletResponse resp) {
    // method logic goes here
  }

  protected void doPost(HttpServletRequest req, HttpServletResponse resp) {

    synchronized(sharedObject) {
      // method logic goes here
    }

  }

  protected void doPut(HttpServletRequest req, HttpServletResponse resp) {

    synchronized(this) {
      // method logic goes here
    }
  }
}

In the example above, only one thread may execute the same request method at-a-time, though it is possible (for example) for one thread to execute doPost() while another is executing doGet().

If you don't understand why this is, then I recommend you do some reading on concurrent programming in Java before investigating your problem further.

Don
I havent got any mention of SingleThreadModel in my code - it extends HttpServlet
RenegadeAndy
Then it's already a multi-threaded servlet
Don
Then it must be my implementation at the start of each get request i call : System.out.println("Im in "); Runtime rt = Runtime.getRuntime(); Process pr = rt.exec(which runs a program and then returns the output - but thats the bit which i think its blocking.... = gives the output:Im in FVFNT01 STOP_IDLE FVFNT03 STOP_IDLE FVFNT16 STOP_IDLE FVFNT17 STOP_IDLEIm in FVFNT01 STOP_IDLE FVFNT03 STOP_IDLE FVFNT16 STOP_IDLE FVFNT17 STOP_IDLEIm in FVFNT01 STOP_IDLE FVFNT03 STOP_IDLE FVFNT16 STOP_IDLE FVFNT17 STOP_IDLEIm in FVFNT01 STOP_IDLE FVFNT03 STOP_IDLE FVFNT16 STOP_IDLE FV
RenegadeAndy
I think its because the Runtime.GetRuntime() is static - meaning there is only one call to that at one time.... how do i spin off child processes without this restriction then?
RenegadeAndy
"static - meaning there is only one call to that at one time" -- this isn't correct. That is synchronized you're talking about. Even if it was synchronized, simple getter returns quickly anyway.
Peter Štibraný
But it looks like the getRuntime() is blocking,,,i.e it only has 1 to hand out at one time?
RenegadeAndy
the description of getRuntime() is : Returns:the Runtime object associated with the current Java application. Making me think there is only 1.
RenegadeAndy
I had a look at the implementation of `Runtime.getRuntime()` and there is no synchronization
Don
Dam - so why is this happening?
RenegadeAndy
If I knew the answer, I would have told you. As I don't have access to the code, all I can do is provide you with the information that might help you solve the problem yourself.
Don
this is the code : http://pastebin.com/WNSp8BwV
RenegadeAndy
A: 

Make sure your requests are using different HTTP connections and check your tomcat configuration if it permits more than 1 thread (by default it does, so unless you've changed it, it should be OK).

Peter Štibraný
When you say different connections - 10 requests from localhost - localhost wouldnt satisfy this would it?
RenegadeAndy
Localhost is ok, but there is difference between sending 10 requests over 1 connection, or 10 requests over 10 connections. If all requests are coming over single connection, they will be processed sequentially.
Peter Štibraný
+1  A: 

The problem is in your test client. It is firing requests synchronously. It should fire requests asynchronously, then the servlet will be able to do the same :)

Roughly the same question was asked 4 days ago, I've posted an answer with a code example how the test client should look like: Servlet requests are executed sequentially for no apparent reason in Glassfish v3. You may find it useful as well.

BalusC
My test client is my web browser... Are you suggesting testing firing requests from different hosts is an answer?
RenegadeAndy
No, firing requests in different threads (asynchronously) is the answer. You're (basically, the webbrowser is) firing all requests in single thread (synchronously). Do I have to copypaste the linked answer here so that you read it? :)
BalusC
lol no ill go read it
RenegadeAndy
Right, so in a deployed scenario, this would not be a problem as requsts would be entering asynchronously.
RenegadeAndy