Rafael Winterhalter

About Rafael Winterhalter

Rafael is a software engineer based in Oslo. He is a Java enthusiast with particular interests in byte code engineering, functional programming, multi-threaded applications and the Scala language.

Object-based micro-locking for concurrent applications by using Guava

One of the presumably most annoying problems with writing concurrent Java applications is the handling of resources that are shared among threads as for example a web applications’ session and application data. As a result, many developers choose to not synchronize such resources at all, if an application’s concurrency level is low. It is for example unlikely that a session resource is accessed concurrently: if request cycles complete within a short time span, it is unlikely that a user will ever send a concurrent request using a second browser tab while the first request cycle is still in progress. With the ascent of Ajax-driven web applications, this trusting approach does however become increasingly hazardous. In an Ajax-application, a user could for example request a longer-lasting task to complete while starting a similar task in another browser window. If these tasks access or write session data, you need to synchronize such access. Otherwise you will face subtle bugs or even security issues as it it for example pointed out in this blog entry.

An easy way of introducing a lock is by Java’s synchronized keyword. This example does for example only block a request cycle’s thread if a new instance needs to be written to the session.

HttpSession session = request.getSession(true);
if (session.getAttribute("shoppingCart") == null) {
  synchronize(session) {
    if(session.getAttribute("shoppingCart")= null) {
      cart = new ShoppingCart();
      session.setAttribute("shoppingCart");
    }
  }
}
ShoppingCart cart = (ShoppingCart)session.getAttribute("shoppingCart");
doSomethingWith(cart);

This code will add a new instance of ShoppingCart to the session. Whenever no shopping cart is found, the code will acquire a monitor for the current user’s session and add a new ShoppingCart to the HttpSession of the current user. This solution has however several downsides:

  1. Whenever any value is added to the session by the same method as described above, any thread that is accessing the current session will block. This will also happen, when two threads try to access different session values. This blocks the application more restrictive than it would be necessary.
  2. A servlet API implementation might choose to implement HttpSession not to be a singleton instance. If this is the case, the whole synchronization would fail. (This is however not a common implementation of the servlet API.)

It would be much better to find a different object that the HttpSession instance to synchronize. Creating such objects and sharing them between different threads would however introduce the same problems. A nice way of avoiding that is by using Guava caches which are both intrinsically concurrent and allow the use of weak keys:

LoadingCache<String, Object> monitorCache = CacheBuilder.newBuilder()
       .weakValues()
       .build(
           new CacheLoader<String, Object>{
             public Object load(String key) {
               return new Object();
             }
           });

Now we can rewrite the locking code like this:

HttpSession session = request.getSession(true);
Object monitor = ((LoadingCache<String,Object>)session.getAttribute("cache"))
  .get("shoppingCart");
if (session.getAttribute("shoppingCart") == null) {
  synchronize(monitor) {
    if(session.getAttribute("shoppingCart")= null) {
      cart = new ShoppingCart();
      session.setAttribute("shoppingCart");
    }
  }
}
ShoppingCart cart = (ShoppingCart)session.getAttribute("shoppingCart");
doSomethingWith(cart);

The Guava cache is self-populating and will simply return a monitor Object instance which can be used as a lock on the shared session resource which is universially identified by shoppingCart. The Guava cache is backed by a ConcurrentHashMap which avoids synchronization by only synchronizing on the map key’s hash value bucket. As a result, the application was made thread safe without globally blocking it. Also, you do not need to worry about running out of memory sice the monitors (and the related cache entries) will be garbage collected if they are not longer in use. If you do not use other caches, you can even consider soft references to optimize run time.

This mechanism can of course be refined. Instead of returning an Object instance, one could for example also return a ReadWriteLock. Also, it is important to instanciate the LoadingCache on the session’s start up. This can be achieved by for example a HttpSessionListener.
 

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

Leave a Reply


9 − eight =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close