Win a copy of Kotlin in Action this week in the Kotlin forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

static initialization block?  RSS feed

 
Mark Gandy
Greenhorn
Posts: 10
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I have a utility class that is accessed by a number of reports concurrently in a webapp. The class has a static HashMap member variable that loads some options from the database. The HashMap is loaded only once, when the first report runs, and there are a number of methods that read from the HashMap. Currently, any method that reads from the HashMap is synchronized, something like this:



But I don't want to synchronize all the methods that are reading from the HashMap as this is slowing the app down.
I thought about using a static initialization block:



So when the first thread calls ReportOptions.readOptions("key") the options will be loaded before reading.
But the big question is - is the static block guaranteed to complete before another thread comes along to read?

I have a feeling the answer is no...if this is the case, any ideas on another solution?
Having to synchronize all methods that read from the HashMap seems like a high price to pay for the initial load (which takes just a few seconds)

thanks in advance
mark
 
Ulf Dittmer
Rancher
Posts: 42972
73
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Having to synchronize all methods that read from the HashMap seems like a high price to pay for the initial load

Indeed, and there's no need for that as long as the HashMap doesn't change after the initial setup.

If this is a web app then you could do the setup in a servlet context listener (which is guaranteed to run before any requests are processed).

You could also initialize the Map in a static initialization block like you had planned, but protect access to it by an instance of java.util.concurrent.locks.ReentrantReadWriteLock, which lets multiple threads read the Map at any given time (w/o noticeable overhead), but only a single thread write to it.
 
paresh vernekar
Ranch Hand
Posts: 52
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ulf and Mark,

If I understand correctly, what you guys are saying, even if a static initialization block is complete there may be other threads trying to access the map
My understanding is that the code in the static block would be executed at class load time and hence would have been completed (assuming there are no exceptions) when the webapp is loaded in the container and before any report requests have been received.

Hence, there may not be any need to protect access to the static block using the Lock...
Do let me know if I am missing something.

However, the suggestion of using the listener with a web-app seems to be a better approach as compared to using static block

Thanks,
Paresh
 
Mike Simmons
Ranch Hand
Posts: 3090
14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Or you could do something like this:

The role of "synchronized" above is purely to create a memory barrier, forcing the JVM to make the effects of the initialization visible to all threads before the reference is seen by any other threads.
 
Mark Gandy
Greenhorn
Posts: 10
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks all for your suggestions - the webapp listener is definitely a good approach.
I do like the simplicity of Mike's solution - are you saying that if I initialize in this way, then it is guaranteed to complete before any un-synchronized methods in ReportOptions (from any thread) are run?
But I don't understand why loadOptions() is synchronized...


The role of "synchronized" above is purely to create a memory barrier, forcing the JVM to make the effects of the initialization visible to all threads before the reference is seen by any other threads.


I've re-read this numerous times but am unable to grasp what you mean - I thought all synchronized does is get a lock? I'm obviously missing something...
 
Mike Simmons
Ranch Hand
Posts: 3090
14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, synchronization does do more than obtain a lot - it has consequences for whether and how the compiler may re-order operations to make them more efficient. This re-ordering has no effect for single-threaded programs, but can yield very confusing results for multi-threaded programs, unless proper synchronization (or other concurrency techniques) are observed.

However, I don't want to get into it here, especially as I have realized that my previous code was wrong. Synchronization should have no effect there - or rather, it will not necessarily have any effect. It can't be used for any memory guarantees since only one thread ever shown using sync on the class object. Synchronization is sonly meaningful for two different actions that sync on the same lock. So, never mind.

Actually I was reviewing the JLS rules for this stuff, and I'm pretty sure that the original static initializer idea will work, without any additional synchronization. So will my code, even without the use of synchronized keyword. The details are found in JLS 12.4.2. Basically, the JVM will make sure the class is fully initialized before any thread can use any method or field of the class. It does some synchronization automatically to ensure this, but this is transparent to the programmer. And the need for synchronization goes away entirely once the class is marked fully initialized.

Here's a simple demo to see the effect on your own system:

This creates five threads that try to read the static field Foo.s. Initialization doesn't start until after the first thread trieds to read s, but none of the threads are able to see s until initialization completes. This works without any use of synchronized, or even final.
 
Mark Gandy
Greenhorn
Posts: 10
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks very much Mike - very interesting.
The demo does indeed show that the static block will complete first.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!