"Punyansky, Alex" wrote:
> Hi,
>
> I'm creating a struts application and trying to figure out how I can
> cache data using ActionServlet in application scope. The info can be
> refreshed during a day, and application has to be available 24/7 ( so
> it's not possible to restart the servlet and refresh cache). E.g.
> product list that can be changed during a day.
>
Caching in application scope sounds like a pretty good idea.
>
> Also the problem that I encounter with any approach is that I'll have to
> make all access methods synchronized. Since data will change rarely, it
> will be very inefficient to make getters synchronized. Did anybody solve
> this problem? Is it better to have static class that will serve as cache
> instead of putting data in application scope?
>
Having a static class, rather than an object in applciation scope, makes
absolutely no difference on whether or not you would need to synchronize
your getter methods. You still have the same contention issues to deal
with.
Whether or not you can avoid the "synchronized" calls depends to some degree
on how you are storing the data in your cached object. In cases where the
"set" method updates something atomically (i.e. a byte or a short on most
architectures), then you can probably get away without the synchronized
call. However, if you're updating something that takes more than one
instruction in the JVM (and that includes things like storing a reference to
a Java object, because on many JVMs that is two 16-bit instructions that are
*not* guaranteed to happen atomically), there is the remote possibility of a
race condition that will cause problems.
One approach to this might be something like the following:
* Define your cache object with no synchronization on the getters,
and no "public" setters (i.e. it appears to be immutable from the
perspective of an applciation class that uses it).
* Provide private means (constructor arguments or package-scope
setter methods) to initialize the properties of the cache object.
* When it is time to update the cache, follow this policy:
- Create a *new* instance of the cache object class,
- Initialize its properties to current values, using the
private setters
- Do a getServletContext().setAttribute() call to replace
the existing application-scope cache object with the
new one.
In doing this, you do not need to synchronize the getters, because the cache
object instance is immutable. A running request will always see either the
previous cache object or the new one (depending on whether their call to
getAttribute() completed before or after the setAttribute() call).
However, after all is said and done, the performance improvement from
avoiding synchronized getters is not likely to be very large, unless each
request performs a fairly large number of accesses to the cached data. This
is increasingly true on newer JVMs (1.2 and 1.3), because the cost of
synchronization has been reduced in each succeeding generation.
So, you might want to just start out with synchronized getters and only try
the above tricks if performance tuning demonstrates that you've got a
problem ...
>
> Thanks
Craig McClanahan