• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Servlet instance variables and volatile

 
Greenhorn
Posts: 18
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi everybody,

Here is the code from SUN Java EE tutorial demonstrating how to initialize A Servlet.



Why bookDB hasn't been made volatile?
The variable bookDB has been set by a thread executing init() and later read by another thread that executing doGet().
Since it's not volatile so there is no guarantee that the thread executing doGet() will see the consistent value of the variable (or will see it at all).

Before I've learned about the concerns about java memory model, I also initialized Servlet this way and the code has been working quite well so far.

My question are that
1. Is the above code considered non-thread-safe both for old and new java memory model?
2. If it's not thread-safe then why it's been used pretty widely and it seems to work fine.
I've googled around and I couldn't find any source that strongly suggest using volatile in initializing Servlet instance variable from init() method.

Here is what I found in Concurrent Programming in Java

On most current JVM implementations and platforms, even those employing multiple processors, detectable visibility failures rarely occur.
The use of common caches across threads sharing a CPU, the lack of aggressive compiler-based optimizations, and the presence of strong cache consistency hardware
often cause values to act as if they propagate immediately among threads



So the above code is able to work as we expected just because the platform it's running on is exceptional smart?

Thanks in advance


 
Ranch Hand
Posts: 423
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

chatchai chailuecha wrote:
Why bookDB hasn't been made volatile?
The variable bookDB has been set by a thread executing init() and later read by another thread that executing doGet().
Since it's not volatile so there is no guarantee that the thread executing doGet() will see the consistent value of the variable (or will see it at all).


Servlets can be started and run only by the web container (web server - like Tomcat, JBoss, WebSphere etc.).
Servlets cannot run as standalone java applications.
Requests from the client (from his web browser) are not serviced directly by the servlet, but are directed to the web server first,
and then the web server decides to which servlet this request should be passed.
The web containter load/initializes servlet (if it was not initlailized before), then passes the request to the servlet from the client.
The web container guarantees than the request cannot be passed to the servlet until servlet's initialization is finished
- so there is no need to explicitly synchronize code in the init() method.
Look here: http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/Servlets4.html

Requestts from the servlet to getServletContext().getAttribute("bookDB"); and getServletContext().setAttribute("bookDB", value);
are synchonized by the web container, so there is no need to synchronize this in the servlet code.
 
chatchai chailuecha
Greenhorn
Posts: 18
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Ireneusz Kordal wrote:

The web container guarantees than the request cannot be passed to the servlet until servlet's initialization is finished
- so there is no need to explicitly synchronize code in the init() method.

Requestts from the servlet to getServletContext().getAttribute("bookDB"); and getServletContext().setAttribute("bookDB", value);
are synchonized by the web container, so there is no need to synchronize this in the servlet code.



Hi Ireneusz , thanks for your reply.
My concern is not about race condition and mutual exclusiveness. The problem is the visibility of the variable across multiple thread.

The bookDB variable has been updated by a thread and then later read by another thread. Although the Servlet container guarantee that
init() will be called before any thread enter doGet/doPost but ,according to java memory model, the thread executing doGet may not see
the updated value unless the variable is volatile.
 
Bartender
Posts: 4179
22
IntelliJ IDE Python Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

chatchai chailuecha wrote:

Ireneusz Kordal wrote:

The web container guarantees than the request cannot be passed to the servlet until servlet's initialization is finished
- so there is no need to explicitly synchronize code in the init() method.

Requestts from the servlet to getServletContext().getAttribute("bookDB"); and getServletContext().setAttribute("bookDB", value);
are synchonized by the web container, so there is no need to synchronize this in the servlet code.



Hi Ireneusz , thanks for your reply.
My concern is not about race condition and mutual exclusiveness. The problem is the visibility of the variable across multiple thread.

The bookDB variable has been updated by a thread and then later read by another thread. Although the Servlet container guarantee that
init() will be called before any thread enter doGet/doPost but ,according to java memory model, the thread executing doGet may not see
the updated value unless the variable is volatile.



That is not true - the memory model says the caches will be synched whenever a synchronization barrier is crossed, and volatile is a way of forcing a synchronization barrier (see the JMM for the side effects for volatile). From the Servlet spec we are told that the Servlet must complete the init() phase before any request can be processed, I haven't looked at the servlet spec to see if it states in more detail how this is performed, but in Java the only practical way to make sure that one section of code is processed before other threads can access other sections of code is through the use of synchronized blocks, which of course leads to synchronization barriers and synchronizing memory caches.
 
chatchai chailuecha
Greenhorn
Posts: 18
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Steve Luke wrote:
That is not true - the memory model says the caches will be synched whenever a synchronization barrier is crossed, and volatile is a way of forcing a synchronization barrier (see the JMM for the side effects for volatile).


^
I think we have the same understanding about that.

Steve Luke wrote:
From the Servlet spec we are told that the Servlet must complete the init() phase before any request can be processed, I haven't looked at the servlet spec to see if it states in more detail how this is performed, but in Java the only practical way to make sure that one section of code is processed before other threads can access other sections of code is through the use of synchronized blocks, which of course leads to synchronization barriers and synchronizing memory caches.


^
Do you mean that Servlet containers usually have been implemented in a way that init() is called in a synchronized block and doGet() is also called in
a synchronized block of the same monitor so there will be memory caches synchronizing once a request thread enter doGet()?
 
Bartender
Posts: 4116
72
Mac TypeScript Chrome Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

chatchai chailuecha wrote:Do you mean that Servlet containers usually have been implemented in a way that init() is called in a synchronized block


Before any request is routed to a particular servlet it should be initialized (that is instantiated and the init() method completed)

and doGet() is also called in a synchronized block of the same monitor so there will be memory caches synchronizing once a request thread enter doGet()?


I don't think it's necessary as each request is served by a separate thread.
 
Steve Luke
Bartender
Posts: 4179
22
IntelliJ IDE Python Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

chatchai chailuecha wrote:
Do you mean that Servlet containers usually have been implemented in a way that init() is called in a synchronized block and doGet() is also called in
a synchronized block of the same monitor so there will be memory caches synchronizing once a request thread enter doGet()?



No, that would be a bad thing to put the request into a synchronized block, you would lose the ability to run simultaneous requests. I won't say anything about how it is usually implemented, because I don't know. But if I were doing it I would make a small call to something like waitForInit() in a synchronized block so each thread, while checking to see if the init() method is complete, would pass through a memory barrier. This would be necessary anyway since synchronization is the only way to get the request threads to wait for the init() to complete, should they be called prematurely.
 
Ranch Hand
Posts: 443
3
Eclipse IDE C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I've had a quick look at a servlet spec (not the latest) and it doesn't seem to guarantee happens before ordering though init will execute in a single thread prior to get / put as you say that wouldn't guarantee visibility on its own (if anyone has found some documentation on this post please), though I would expect a container to honour this. I guess another way they could achieve this would be have the init thread terminate and all request threads be created after the init thread which would give you the appropriate sequence points but that doesn't seem that efficient (thread creation / destruction).

PS Synchronizing put / get would give you the SingleThreadModel not recommended.
 
rubbery bacon. rubbery tiny ad:
a bit of art, as a gift, the permaculture playing cards
https://gardener-gift.com
reply
    Bookmark Topic Watch Topic
  • New Topic