Fushi
asked on
Servlets, performance, threads and synchronization issues
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
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
ASKER
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
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
> 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.
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.
ASKER
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?
.
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?
.
you can have application scope variable, and also session scope variables.
can u post your servlet code.
can u post your servlet code.
ASKER
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.app User;
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(CO NTENT_TYPE );
PrintWriter out = response.getWriter();
//clear the error message
session.setAttribute("erro rMsg", errorMsg);
//get the selection parameter
String mySelection = request.getParameter("sele ction");
//convert to int
int menuSelection = myUtility.stringToInt(mySe lection);
//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("a ppUser")!= null)
{
myForwardPath = "/stepMenu.jsp";
}
else
{
errorMsg = login(request, response, 1);
if (errorMsg.equals(""))
{
myDate = new java.util.Date();
appUser myuse = (appUser)session.getAttrib ute("appUs er");
mili = myDate.getTime();
System.out.println(myuse.g etAppId() + "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("dea dlines")!= 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("erro rMsg", errorMsg);
//move to next object using the myForwardPath variable
RequestDispatcher dispatch = this.getServletContext().g etRequestD ispatcher(
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(requ est.getPar ameter("us ername"),
request.getParameter("pass word"),
request.getHeader("user-ag ent"),
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("appU ser", myUser);
}
}
catch (Exception e)
{
e.printStackTrace();
errorMsg="Unable to access user profile";
}
myDate = new java.util.Date();
appUser myuse = (appUser)session.getAttrib ute("appUs er");
mili = myDate.getTime();
System.out.println(myuse.g etAppId() + "Time: " + mili);
return errorMsg;
}
public String lookupDeadlines(HttpServle tRequest request, HttpServletResponse response)
{
String errorMsg="";
session = request.getSession(true);
myDAO = new mainDAO();
try
{
session.setAttribute("dead lines", 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("app User") == null) {
//do nothin...user profile is empty.
errorMsg =
"You did not log in, or you have already terminated your session";
}
else {
session.removeAttribute("a ppUser");
//session.setAttribute("ap pUser", 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("appU ser");
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("weeeee eeeeeeeeee eeeeeeeeee eee");
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
package edu.asu.map.controllers;
//import Servlet packages
import javax.servlet.*;
import javax.servlet.http.*;
import edu.asu.map.containers.app
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
ServletException, IOException {
java.util.Date myDate;
long mili;
//declare and instantiate the session object
session = request.getSession(true);
response.setContentType(CO
PrintWriter out = response.getWriter();
//clear the error message
session.setAttribute("erro
//get the selection parameter
String mySelection = request.getParameter("sele
//convert to int
int menuSelection = myUtility.stringToInt(mySe
//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("a
{
myForwardPath = "/stepMenu.jsp";
}
else
{
errorMsg = login(request, response, 1);
if (errorMsg.equals(""))
{
myDate = new java.util.Date();
appUser myuse = (appUser)session.getAttrib
mili = myDate.getTime();
System.out.println(myuse.g
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("dea
{
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("erro
//move to next object using the myForwardPath variable
RequestDispatcher dispatch = this.getServletContext().g
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(requ
request.getParameter("pass
request.getHeader("user-ag
flag));
myDate = new java.util.Date();
mili = myDate.getTime();
System.out.println(myUser.
if(myUser.getErrorCode()!=
{
//problem with login
errorMsg="Wrong username or password";
}
else
{
session.setAttribute("appU
}
}
catch (Exception e)
{
e.printStackTrace();
errorMsg="Unable to access user profile";
}
myDate = new java.util.Date();
appUser myuse = (appUser)session.getAttrib
mili = myDate.getTime();
System.out.println(myuse.g
return errorMsg;
}
public String lookupDeadlines(HttpServle
{
String errorMsg="";
session = request.getSession(true);
myDAO = new mainDAO();
try
{
session.setAttribute("dead
}
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("app
//do nothin...user profile is empty.
errorMsg =
"You did not log in, or you have already terminated your session";
}
else {
session.removeAttribute("a
//session.setAttribute("ap
}
}
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("appU
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("weeeee
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
> implements SingleThreadModel{
thats also unnecessary
thats also unnecessary
ASKER
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,
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,
> 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.
then why have them at all :)
They are unnecessary freom what I can see. Just use local vars instead.
> 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.
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.
ASKER
> 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?)
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?)
ASKER
> 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
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
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
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!
:-)
:)
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?