Solved

Servlets, performance, threads and synchronization issues

Posted on 2004-09-09
17
358 Views
Last Modified: 2013-11-24
Hello Experts,

We have an application that uses the JSP/Servlet model.  Info from the jsp is submitted to a servlet that deals with business objects and DAO's. We keep  some information in HttpSession objects and recently we have discovered that the sessions can get mixed up if there are multiple request coming into the servlet at close time intervals.  For example if three of us try to log in, I will log in as somone else and someone will log in as me, etc....This is due to the fact that from my understanding sessions are application wide and all threads issued by the servlet have access to those resources.  Therefore when a few threads are running concurrently they can “get confused” as to which session belongs to who.  

We have found 2 solutions to this problem.

1.      synchronizing the servlets service(). The problem with this is that it lock the service method until the first thread has finished working with it, therefore with many concurrent users the queue will grow significantly and that will hurt the performance
2.      Having the servlet implement SingleThreadModel interface.  Not sure how this works but from what I understand it causes the servlet container to create a pool of servlet instances and execute one thread in each instance for each request… This seems to have a better performance then synchronizing the service method (as per the tests that we ran) but I can see how this can soon become very costly if the server has to have 500 servlet instances in the pool.  The other thing that worries me is that I am not sure how and why this really works…

From the research done it seems that both the methods mentioned are not very good and synchronizing access to the shared resource should be the way to go but putting a synchronized scriplet around accessing the session doesn’t do jack….No one really mentions a working solution.

Please let me know if any of you have encountered a similar problem and how you dealt with it.  Also if anyone could shine some light on the singleThreadModel interface, I would greatly appreciate it!


Thanks,

-w
0
Comment
Question by:Fushi
  • 7
  • 7
  • 2
  • +1
17 Comments
 
LVL 1

Expert Comment

by:gloverkcn
Comment Utility
The SingleThreadModel interface basically tells the appserver that only one instance of the  app can be run at once.  So if you get 20 connections they have to wait their  turn  to use the application.  I wouldn't recommend using it since it will really hamper performance.

I haven't seen the issue with multiple log-ins before.  How are you handling the log-in process?  Are you using roles?  Form-Based Authentication? Is a servlet handling the log-in log-out?
0
 
LVL 2

Author Comment

by:Fushi
Comment Utility
We ran tests (showing execution speed with miliseconds ) and you are not correct . With singleThreadModel there are multiple instances of the servlet (not threads)  being executed at the same time. What you are sayiong happens if you synchronize the service method.  So the problem with SingleThreadModel is not the queue, it is the amount of resources that it incolves to create and keep track of a pool of servlet instances.

This doesn't only happen with logins...It happens when accessing any shared (session) resource.  

The process is as follows.

Jsp form is submited to a servlet's service()  method that issues a call to let's say a login() that calls a DAO that accesses a database and returns some valus that are the returned to the login() which put's it in a session object.  The that session object is used by multiple jsp's
0
 
LVL 92

Expert Comment

by:objects
Comment Utility
> This is due to the fact that from my understanding sessions are application wide

Each user has there own session so this should not be a problem.

Does your servlet have any member variables, if so you should probably get rid of them as servlets are best kept stateless.
0
 
LVL 2

Author Comment

by:Fushi
Comment Utility
that is also what I thought, but after further research as I explained sessions are application scope variables and since servlets are multithreaded, if multiple threads try to access different sessions in close time intervals different threads grab different sessions and that is why there is a need for synchronization....as I said this is not a simply theoretic problem, we were testing the app and were able to log in as different people if the 3 of us clicked submit at the same time....

When you say member variables, do you mean gloabal class variables? I do have them, and my HttpSession object is actually declared (but not initialized) as a global variable....I think I see where you are going with this....So where should I declare my session, in my service method and any other methods that use it? why wouldn't I just want to declare it as a gloabl variable and then reinitialize it whenever I need to?
.  

0
 
LVL 92

Expert Comment

by:objects
Comment Utility
you can have application scope variable, and also session scope variables.

can u post your servlet code.
0
 
LVL 2

Author Comment

by:Fushi
Comment Utility
Please keep in mind this is work in progresss....please concentrate on case 0 of the service()

package edu.asu.map.controllers;

//import Servlet packages
import javax.servlet.*;
import javax.servlet.http.*;
import edu.asu.map.containers.appUser;
import com.sybase.jdbc2.jdbc.*;


import edu.asu.map.common.*;

//import io package
import java.io.*;

import java.net.*;

import java.sql.*;
import java.util.*;
import java.util.Vector.*;

//begin mainMenuLogic Servlet Class
public class controllerMainMenu
    extends HttpServlet implements SingleThreadModel{

//create the session object
HttpSession session;
mainDAO myDAO;
public static Vector myStates;
//Declare an empty error message
String errorMsg="";

//Set response content type
  static final private String CONTENT_TYPE = "text/html";
//Declare and initialize class variables
  boolean loginSuccess=false;


//default init()
  public void init() throws ServletException {
  //load state values and put them in a static variable
  loadStates();
 
  }

//default destroy()
  public void destroy() {}

//begin service method declaration
  public void service(HttpServletRequest request, HttpServletResponse response) throws
      ServletException, IOException {
java.util.Date myDate;
long mili;
    //declare and instantiate the session object
    session = request.getSession(true);


    response.setContentType(CONTENT_TYPE);
    PrintWriter out = response.getWriter();

    //clear the error message
   
    session.setAttribute("errorMsg", errorMsg);
    //get the selection parameter
    String mySelection = request.getParameter("selection");

    //convert to int
    int menuSelection = myUtility.stringToInt(mySelection);

    //declare and initialize variable to hold the path of the redirect
    String myForwardPath = "";

    switch (menuSelection) { //start switch
      //login request received, call login
      case 0:
        if(session.getAttribute("appUser")!=null)
        {
           myForwardPath = "/stepMenu.jsp";
        }
        else
        {
        errorMsg = login(request, response, 1);
        if (errorMsg.equals(""))
        {
          myDate = new java.util.Date();
         
          appUser myuse = (appUser)session.getAttribute("appUser");
           mili = myDate.getTime();
          System.out.println(myuse.getAppId() + "Time: " + mili);
              myForwardPath = "/stepMenu.jsp";

        }
        else {
          myForwardPath = "/login.jsp";
          }
        }
           break;
           //end case 0 - login requested


      //new login request call newLogin()
      case 1:
        errorMsg = login(request, response, 0);
        if (errorMsg.equals("")) {

          if(verify(request).equals(""))
          {
              myForwardPath = "/stepMenu.jsp";
          }
          else
          {
              myForwardPath = "/error.jsp";
          }

        }
        else {
          myForwardPath = "/newLogin.jsp";
        }

        break;
      //end case 1 - new login requested

      //app deadlines request
      case 2:

      if (session.getAttribute("deadlines")!=null)
      {
         myForwardPath = "/mainMenu.jsp";
      }
      else
      {
        errorMsg = lookupDeadlines(request, response);
        if (errorMsg.equals("")) {
          myForwardPath = "/mainMenu.jsp";
        }
        else {
          myForwardPath = "/errorPage.jsp";
        }
      }

      break;//end app deadlines request

      //log out
      case 3:
      errorMsg = logout(request, response);
      if (errorMsg.equals("")) {
        myForwardPath = "/logout.jsp";
        }
      else {
        myForwardPath = "/errorPage.jsp";
        }

      break;




      default:
        out.println("Unknown request");
        break;

    } //end switch


    session.setAttribute("errorMsg", errorMsg);

     //move to next object using the myForwardPath variable
    RequestDispatcher dispatch = this.getServletContext().getRequestDispatcher(
        myForwardPath);



    dispatch.forward(request, response);


//end service method declaration
  }

  public String login(HttpServletRequest request, HttpServletResponse response, int flag)
  {
    String errorMsg="";
    session = request.getSession(true);
    appUser myUser;
    myDAO = new mainDAO();
 java.util.Date myDate;
 long mili;
 
        try
        {
          myUser=(myDAO.getUser(request.getParameter("username"),
                                                        request.getParameter("password"),
                                                        request.getHeader("user-agent"),
                                                        flag));
          myDate = new java.util.Date();
          mili = myDate.getTime();
          System.out.println(myUser.getAppId() + "Time: " + mili);
          if(myUser.getErrorCode()!=3)
          {
            //problem with login
            errorMsg="Wrong username or password";
          }
          else
          {
             session.setAttribute("appUser", myUser);


          }

        }
        catch (Exception e)
        {
          e.printStackTrace();
          errorMsg="Unable to access user profile";
        }
 
    myDate = new java.util.Date();
    appUser myuse = (appUser)session.getAttribute("appUser");
    mili = myDate.getTime();
    System.out.println(myuse.getAppId() + "Time: " + mili);

    return errorMsg;

  }

public String lookupDeadlines(HttpServletRequest request, HttpServletResponse response)
{
  String errorMsg="";
  session = request.getSession(true);
  myDAO = new mainDAO();

  try
  {
  session.setAttribute("deadlines", myDAO.getDeadlines());
  }
  catch(Exception e)
  {
    e.printStackTrace();
    errorMsg="Unable to retrieve Application deadlines...";

  }

  return errorMsg;
}

public String logout(HttpServletRequest request, HttpServletResponse response)
{
  session = request.getSession(true);
  String errorMsg="";

  try
  {

    if (session.getAttribute("appUser") == null) {
      //do nothin...user profile is empty.
      errorMsg =
          "You did not log in, or you have already terminated your session";
    }
    else {
      session.removeAttribute("appUser");

      //session.setAttribute("appUser", null);
    }
  }
  catch (Exception e)
  {
    e.printStackTrace();
    errorMsg =
          "You did not log in, or you have already terminated your session";
  }

  return errorMsg;
}
//end mainMenuLogic Servlet Class

public String verify(HttpServletRequest request)
{
  session = request.getSession(true);
  String errorMsg = "";
  try
  {
    appUser myUser = (appUser) session.getAttribute("appUser");

    if (myUser.getAppId()>0)
    {
      errorMsg="";
    }
    else
    {
      errorMsg="You are not authenticated. Please authenticate to view this page";
    }

  }
  catch(Exception e)
  {
    e.printStackTrace();
    errorMsg="You are not authenticated. Please authenticate to view this page";
  }


  return errorMsg;
}
     
public void loadStates()
{
  myDAO = new mainDAO();
  try
  {
  myStates = myDAO.getStates();
  System.out.println("weeeeeeeeeeeeeeeeeeeeeeeeeeee");
  }
  catch(Exception e)
  {
    e.printStackTrace();
  }


}

}


0
 
LVL 92

Accepted Solution

by:
objects earned 300 total points
Comment Utility
You need to get rid of all of the following member variables so your servlet is stateless:

//create the session object
HttpSession session;
mainDAO myDAO;
public static Vector myStates;
//Declare an empty error message
String errorMsg="";

//Declare and initialize class variables
  boolean loginSuccess=false;


If you need to store any application wide values then store them in the application context,
and if you have any session values to store then store them in the session.
0
 
LVL 92

Expert Comment

by:objects
Comment Utility
>  implements SingleThreadModel{

thats also unnecessary
0
Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

 
LVL 2

Author Comment

by:Fushi
Comment Utility
well as I said implements SingleThreadModel will be unnecessary if I won't get any resource conflicts (this interface makes sure that there are multiple instances of the servlet created for each request)....and when you say to "store them in the session values", I am storring in a session....the HttpSession object...
I have no problems with my aplication wide variables...however as I said my session variables get mixed up....I will try to get rid of my member variables tomorrow as I need more people in the office to test this simoltaneously.

So why do member variables couse conflicting access to  session resources...especially since I am really not even initializing any of them (well except for errorMessgae)? I mean we tested this over and over agian with 3 people. We had 3 people try to log into the app ion close time intervals and eveything was correct...meaning the righ info for each session was being pulled from the database and then back to the servlet and it had the correct info in the session object up yuntill the request was forwarde to the jsp...That is when things got mixed up (I would get sombody elses session info, etc). This has seriously confused me since up untill that moment I was sure session objects are session (user) specific....any explanations? thanks,
0
 
LVL 92

Expert Comment

by:objects
Comment Utility
> since I am really not even initializing any of them (well except for errorMessgae)?

then why have them at all :)
They are unnecessary freom what I can see. Just use local vars instead.
0
 
LVL 92

Expert Comment

by:objects
Comment Utility
> So why do member variables couse conflicting access to  session resources

you get a request from user A, which sets the member session var to refernce their session
before that request is finished another request comes from user B which sets the member session var to reference their session.
user A's requests then access the member session var which is now actually User B's session.
0
 
LVL 2

Author Comment

by:Fushi
Comment Utility
> then why have them at all :)

I guess I'm just lazy so if I just declare the vars then  I can just re-initialize them in the methods I'm using it in...I thought that was ok (or am I just being too lazy?)

0
 
LVL 2

Author Comment

by:Fushi
Comment Utility
> user A's requests then access the member session var which is now actually User B's session.

That makes sense... I will try to get rid of member vars tomorrow and let you know if this helped...Thanks for hanging with me on this

-w
0
 
LVL 35

Assisted Solution

by:girionis
girionis earned 100 total points
Comment Utility
> So why do member variables couse conflicting access to  session resources..

To understand what is going on you have to know how servlets work. What usually happens is that the servlet container instantiates one servlet (this depends on the container though, some might instantiate several of them) and each request on this servlet will be served by a different thread, meaning that the container spawns a new thread for each request.

Each thread holds a copy of its methods in the stack, so all variables that are declared and used *within* methods are guaranteed to be thread safe. However, member variables live in the heap and they are *shared* between all threads, so they are not guaranteed to be thread safe, unless you make them by synchronizing them.

Maybe this link will help you understand the memory model: http://java.sun.com/docs/books/vmspec/2nd-edition/html/Overview.doc.html#15730
0
 
LVL 2

Author Comment

by:Fushi
Comment Utility
Sure enough, it worked...Thanks to both of you for the solution as well as the explanation, I defenietly feel like I have a better understanding (or more like at least a beggining of an understanding) of memmory allocation....Thanks!
0
 
LVL 92

Expert Comment

by:objects
Comment Utility
:-)
0
 
LVL 35

Expert Comment

by:girionis
Comment Utility
:)
0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Suggested Solutions

After being asked a question last year, I went into one of my moods where I did some research and code just for the fun and learning of it all.  Subsequently, from this journey, I put together this article on "Range Searching Using Visual Basic.NET …
Java Flight Recorder and Java Mission Control together create a complete tool chain to continuously collect low level and detailed runtime information enabling after-the-fact incident analysis. Java Flight Recorder is a profiling and event collectio…
Viewers learn about the “for” loop and how it works in Java. By comparing it to the while loop learned before, viewers can make the transition easily. You will learn about the formatting of the for loop as we write a program that prints even numbers…
Viewers will learn about if statements in Java and their use The if statement: The condition required to create an if statement: Variations of if statements: An example using if statements:

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

8 Experts available now in Live!

Get 1:1 Help Now