[concurrency-interest] Lock free caches

Joe Bowbeer joe.bowbeer at gmail.com
Wed Apr 11 05:34:59 EDT 2007


On 4/11/07, Mike Quilleash <mike.quilleash at subexazure.com> wrote:
>
> I have a performance bottleneck in my code involving
> java.util.regex.Pattern.  Doing Pattern.compile() is slow and I would like
> to cache these across the application (as the pool of used patterns is quite
> small but used regularly), but I want to keep any synchronization to a
> minimum.
>
> I thought about the following which just does a simple check if present and
> build and insert if not.
>
> public class RegexPatternCache
> {
>     private static ConcurrentMap< String, Pattern > patternCache = new
> ConcurrentHashMap< String, Pattern >();
>
>     public static Pattern getRegexPattern( String patternString )
>     {
>         if ( patternCache.containsKey( patternString ) )
>             return patternCache.get( patternString );
>
>         Pattern pattern = Pattern.compile( patternString );
>
>         patternCache.putIfAbsent( patternString, pattern );
>
>         return pattern;
>     }
> }
>
> I believe the above is threadsafe (please correct me if not!), worst case
> being two threads may call getRegexPattern at the same time with the same
> patternString and both compile the pattern.  As this is a deterministic
> operation I don't see any problem with this.  Is this the best way of
> implementing this sort of mini-cache?  Is there an established
> best-practice/pattern for this sort of thing?
>

Your solution is a 'memoization' of getRegexPattern.  There's an
example of this in 'Java Concurrency in Practice' book.  An example
has also been presented at JavaOne.  You should be able to find it in
the 2005 slides.  Maybe 2006.  Look for 'Memoize'.

In your code, the map should be declared final (for completeness).

The fully-articulated example in the slides and book stores a Future
in the map.  This is more efficient in the event that two or more
threads are simultaneously seeking the same new pattern.  It also
leverages putIfAbsent.  (putIfAbsent is not really accomplishing
anything in your code.)

--Joe


More information about the Concurrency-interest mailing list