HttpSession thread safety issues that we ignore

Source: Internet
Author: User

1. Background

Recently reading "Java Concurrency in Practice" (Java Concurrency Combat), where section 1.4 mentions the thread safety of Java Web with the following passage:

Servlets and JPSS, as well as Servlets filters and objects stored in scoped containers like ServletContext and httpsess Ion, simply has to be thread-safe.

Servlets, JSPs, servlet filter, and objects stored in ServletContext, HttpSession must be thread-safe. Meaning there are two points:

1) Servlet, JSP, servlet filter must be thread-safe (the nature of JSP is actually Servlet);

2) objects stored in ServletContext, httpsession must be thread-safe;

Servlets and Servelt filter must be thread-safe, which is generally not a problem, as long as there is no instance attribute in our servlet and servlet filter, or the instance property is immutable object. But the objects stored in ServletContext and httpsession must be thread-safe, which seems to have been overlooked by us all along. In a Java Web project, we often keep a logged-in user in HttpSession, and this user object is a Java bean as defined below:

 Public classUser {Private intID; PrivateString UserName; PrivateString password; // ... ...         Public intgetId () {returnID; }     Public voidSetId (intID) { This. ID =ID; }     PublicString GetUserName () {returnUserName; }     Public voidsetusername (String userName) { This. UserName =UserName; }     PublicString GetPassword () {returnpassword; }     Public voidSetPassword (String password) { This. Password =password; }}

2. Source Code Analysis

The following analysis of why a such Java object is stored in the httpsession is problematic, at least the thread security is not rigorous, there may be concurrency problems.

Tomcat8.0 in the HttpSession source code in Org.apache.catalina.session.StandardSession.java file, the source code is as follows (intercept the part we need):

 Public classStandardsessionImplementsHttpSession, Session, Serializable {//-----------------------------------------------------Instance Variables    /*** The collection of the user data attributes associated with this Session. */    protectedmap<string, object> attributes =NewConcurrenthashmap<>(); /*** Return The object bound with the specified name in this session, or * <code>null</code> if no o     Bject is bound with that name. *     * @paramname Name of the attribute to be returned * *@exceptionIllegalStateException If this method was called on A * invalidated session*/@Override PublicObject getattribute (String name) {if(!isvalidinternal ())Throw Newillegalstateexception (sm.getstring ("StandardSession.getAttribute.ise")); if(Name = =NULL)return NULL; return(Attributes.get (name)); }   /*** Bind An object to this session, using the specified name.     If an object * of the same name was already bound to this session, the object is * replaced. * <p> * After this method executes, and if the object implements * <CODE>HTTPSESSIONBINDINGLISTENER<     ;/code>, the container calls * <code>valuebound () </code> on the object. *     * @paramname name to which the object was bound, cannot be null *@paramvalue Object to being bound, cannot be null *@paramnotify whether to notify session listeners *@exceptionIllegalArgumentException If an attempt are made to add a * non-serializable object in an environment marked DISTR     Ibutable. * @exceptionIllegalStateException If this method was called on A * invalidated session*/     Public voidSetAttribute (String name, Object value,Booleannotify) {        //Name cannot be null        if(Name = =NULL)            Throw Newillegalargumentexception (sm.getstring ("StandardSession.setAttribute.namenull")); //Null value is the same as removeattribute ()        if(Value = =NULL) {removeattribute (name); return; }        // ... ...        //Replace or add this attributeObject unbound =attributes.put (name, value); // ... ...   }   /*** Release All object references, and initialize instance variables, in * preparation for reuse of this objec T.*/@Override Public voidRecycle () {//Reset The instance variables associated with this Sessionattributes.clear (); // ... ...    }    /*** Write A serialized version of this session object to the specified * object output stream. * <p> * <b>implementation note</b>: The owning Manager is not being stored * in the serialized R  Epresentation of this Session.     After calling * <code>readobject () </code>, you must set the associated Manager * explicitly. * <p> * <b>implementation note</b>: Any attribute that's not Serializable * would be unbound fr  Om the session, with appropriate actions if it * implements Httpsessionbindinglistener. If you don't want any such * attributes, being sure the <code>distributable</code> property of the *     Ociated Manager is set to <code>true</code>. *     * @paramstream the output stream to write to * *@exceptionIOException If an input/output error occurs*/    protected voidDowriteobject (ObjectOutputStream Stream)throwsIOException {// ... ...        //accumulate the names of serializable and Non-serializable attributesString keys[] =keys (); ArrayList<String> Savenames =NewArraylist<>(); ArrayList<Object> savevalues =NewArraylist<>();  for(inti = 0; i < keys.length; i++) {Object value=Attributes.get (Keys[i]); if(Value = =NULL)                Continue; Else if((ValueinstanceofSerializable)&& (!exclude (Keys[i]))                {Savenames.add (keys[i]);            Savevalues.add (value); } Else{removeattributeinternal (keys[i],true); }        }        //Serialize the attribute count and the Serializable attributes        intn =savenames.size ();        Stream.writeobject (integer.valueof (n));  for(inti = 0; I < n; i++) {Stream.writeobject (Savenames.get (i)); Try{stream.writeobject (Savevalues.get (i)); // ... ...            }Catch(notserializableexception e) {// ... ...                           }        }    }}

We see all the properties that are stored in each separate httpsession, which are in a separate concurrenthashmap in the store:

Protected Map<string, object> attributes = new concurrenthashmap<> ();

So I can see that Httpsession.getattribute (), Httpsession.setattribute () and so on are all thread-safe.

In addition, if we want to save an object in HttpSession, then the object should be serializable. Otherwise, when the httpsession is persisted, it is discarded and cannot be restored:

else if (value instanceof Serializable)
&& (!exclude (keys[i))) {
Savenames.add (Keys[i]);
Savevalues.add (value);
} else {
removeattributeinternal (Keys[i], true);
}

So from the source of the analysis, we have come to the following conclusions:

1) Httpsession.getattribute (), Httpsession.setattribute () and so on are thread-safe;

2) the object to be saved in the httpsession should be serialized;

Although Getattribute,setattribute is thread-safe, is the following code thread-safe?

Session.setattribute ("user", user);

User user = (user) Session.getattribute ("user", user);

Not thread-safe! Because the user object is not thread-safe, suppose one of the threads performs the following actions:

User user = (user) Session.getattribute ("user", user);

User.setname ("xxx");

Then there is obviously a concurrency problem. Because it appears: there are multiple threads accessing the same object user, and at least one thread is modifying the object. But under normal circumstances, our Java Web program is so written, why is there no problem? The reason for this is that "multiple threads access the same object user in the Web, and at least one thread modifies the object" is rarely seen, because we use httpsession to temporarily save information in memory for quick access, so we generally do not do the following:

Session.setattribute ("user", user);

User user = (user) Session.getattribute ("user", user);

We generally only use the Get method to get information from objects in httpsession, and generally do not call the Set method for "objects obtained from httpsession" to modify it, but instead call setattribute directly to set it up or replace it with a new one.

3. Conclusion

So the conclusion is: if you can guarantee that the set method is not called for "objects obtained from HttpSession", then the object saved in HttpSession can be not thread-safe (because he is a "fact immutable object", and Concurrenthashmap ensured that it was "securely released"); but if you can't guarantee that, then you have to implement "objects that are stored in httpsession must be thread safe." Otherwise, there is a concurrency problem.

The simplest way to make Java Bean thread safe is to add synchronized to all Get/set methods.

HttpSession thread safety issues that we ignore

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.