I've been reading the Head First Servlets and JSP book, and in the section about thread-safety of context attributes and session attributes they show the correct way to synchronize reads and writes of context attributes and session attributes. Taking a look at their sample code for protecting session attributes:
shouldn't the synchronized block be limited to just the writing (or setting) of the session attributes as in the following:
I don't have much experience with threading/concurrency but I've always read that the scope of synchronization should be kept as small as possible. And in the case of this example taken from the book, wouldn't it make more sense to only synchronize the setting of the session attributes?
The first example from the book suggests that their expectation is that the value printed must be the same as the value you put into the session. If the read value must be the same as the written value then you need to put both the read and write in the same synchronized block. Why? If you write "42" to bar, then exit the synchronized block another thread could gain entry to the session, change the value to "21". Then when you try to read bar you get "21" instead of "42" as would be expected. Or worse the second thread could clear the attribute from the session so you would get null.
BTW, you could still shorten the synchronize block by using local variables:
But that sort of short circuits the example.
Joined: Feb 12, 2009
Oh, it never occurred to me another thread could gain entry to the synchronized block before the first thread completed it's out.println(). Just goes to show how little I know about concurrency & multi-threading!
However, as long I am not concerned about the attribute value being printed I could just use my shortened version, right?
That's right, if you don't care about the value once it is set, then you can shortened version. But just keep in mind that any pair of actions which must be performed on the same data should be done in a single synchronized block.
Here is another, perhaps more poignant example. Say you have an item ID for the last item a user purchased stored in the session. You then need to check if the last item purchased qualifies for free shipping so you can inform the user of this info. You may be tempted to do something like this:
Or maybe even this:
So both would be attempts to keep the synchronized block as short as possible, but both would be incorrect. In both cases it would be possible for another thread to intervene. Perhaps the user goes to another page in another tab and buys another item in the time between the getAttribute(lastItem) call and the setAttribute(freeShipping) call. The sequence of events may be:
So since in this example freeShipping is derived and dependent on lastItem, the set for freeShipping must be in the same synchronized block as the get for last item or inconsistant states can occur:
Just something to keep in mind when you are thinking about thread safety.
Joined: Feb 12, 2009
Thanks for the info Steve, it really helps.