ServletContext Object Thread Security

I store a HashMap object in my ServletContext. But a stream of multiple requests reads and modifies this HashMap.

I suppose ServletContext objects are shared between request flows, do I need to synchronize access to this HashMap? Or are there any other better ways to achieve the same?

+7
source share
5 answers

Publishing attributes via ServletContext#setAttribute thread-oriented! This can be obtained from the Java Servlet Specification, chapter 4.5: (...) Any related attribute in the context is accessible to any other servlet that is part of the same network application. (...).

(Reason: making objects available to other servlets also means making them available to other threads. This is only possible with proper synchronization, so synchronization is required for all servlet containers that implement ServletContext#setAttribute ).

The same applies to reading published attributes through ServletContext#getAttribute .

But, of course, if an object like HashMap is shared between different threads, the developer must make sure that the most common object is accessed in an appropriate, thread-safe way! Using ConcurrentHashMap , as already mentioned in other answers to your question, is a possible solution, but does not solve the race conditions when initializing the attribute, since the null check will not be atomic:

 ConcurrentMap<String, Object> shared = (...)servletContext.getAttribute("sharedData"); if (shared == null) { shared = new ConcurrentHashMap<>(); servletContext.setAttribute("sharedData", shared); } 

Therefore, ServletContextListener can be used to initialize the context when starting the web application!


Change: To avoid confusion

From the Java Servlet Specification, we can conclude that sharing attributes between servlets through ServletContext#setAttribute and ServletContext#getAttribute really thread-oriented.

But no matter how it is implemented internally, set/getAttribute can guarantee only the correct publication, it cannot guarantee the correct synchronization if the common attribute is a mutable object that is modified after sharing. This is technically impossible!

Example:

 // servlet 1: Person p = new Person("Keith", "Richards"); context.setAttribute('key', p); // share p p.setName("Ron", "Wood"); // modification AFTER sharing // servlet 2 (some time LATER): Person p = context.getAttribute(); // now, p is guaranteed to be non-null, // but if class Person is not thread-safe by itself, it may be any of // - "Keith Richards" // - "Keith Wood" // - "Ron Richards" // - "Ron Wood" // (depending on the implementation of setName, it may be even worse!) 

As a result, each value of the servlet context attribute must be

  • immutable (through end fields) or effectively immutable, OR
  • mutable, but never mutated after sharing, OR
  • implemented in a thread-oriented manner (e.g. synchronized)

(This is true for all kinds of objects shared by threads in Java, not only in relation to servlet context attributes)

+16
source

As @Artem Moskalev , you can use ConcurrentHashMap and use the putIfAbsent method to store the object / values ​​instead of the simple put method.

I wanted to add this comment below @Artem Moskalev' , but I don't have enough reputation for that.

+4
source

The best way in a multi-threaded environment is to use java.util.concurrent.ConcurrentHashMap . It is designed specifically so that you can read and modify it without any ConcurrentModificationException . However, in the case of iteration, you must synchronize your instance to always get predictive results.

Syncing in context gives you a lot of overhead if you fetch anything else from there in a multithreaded way. Therefore, ConcurrentHashMap is the best solution.

You can read about it here:

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentHashMap.html

A hash table that supports full concurrency fetching and custom expected concurrency for updates. Search operations (including receiving) are usually not blocked, so they may overlap with update operations (including put and remove).

+1
source

Yes, make sure that when changing the HashMap ; It is synchronized or thread safe.

0
source

You need to synchronize your ServletContext object. eg: -

 synchronized(ctx){ //your code here } 
-1
source

Source: https://habr.com/ru/post/958767/


All Articles