Java's AtomicInteger vs. ColdFusion Named-Locking For Incrementing Values

Posted January 5, 2010 at 7:38 PM by Ben Nadel

Tags: ColdFusion

A few weeks ago, I blogged about a caching approach for ColdFusion 9 in which the business logic for "cache key" creation was factored out of the main algorithm. In a spin-off conversation in the comments, Dennis Clark raised the issue of thread safety surrounding my use of an auto-incrementer:

  • id = ++this.autoIncrementer

He claimed that in extremely rare cases, this line of code could actually result in a race condition. While I am not 100% convinced that this is true, I was interested in the solution he suggested: use Java's AtomicInteger rather than a standard int value. I had never heard of an AtomicInteger before; but after looking it up, it appears that Java has a small set of "atomic" data types that are built to provide thread-safe, single-variable mutation without locking (NOTE: avoidance of locking is not guaranteed). Given the fact that these exist, and that the AtomicInteger is built for incrementing, I guess it's only logical to believe the ++ operator is not thread-safe.

Before I looked it up, however, I suggested that a named-lock could be put around the value increment; but what Dennis Clark told me (which the Java docs confirm) is that because the atomic data types don't use locking, they will be more performant. I figured this would be an easy thing to put to the test; in the following demo, I am going to compare the relative speed of incrementing between a ColdFusion named-lock and a Java AtomicInteger:

  • <!--- Create a standard integer. --->
  • <cfset counter = 0 />
  •  
  • <!---
  • Create an atomic integer. This specialized Number class
  • allows us to increment the value without having to worry
  • about thread-safey. NOTE: This class is designed for
  • use with increment / decrement scenarios.
  • --->
  • <cfset atomicCounter = createObject(
  • "java",
  • "java.util.concurrent.atomic.AtomicInteger"
  • )
  • .init()
  • />
  •  
  •  
  •  
  • <!---
  • Now, let's define a method for incrementing. It will work
  • in two ways - both ways will be thread-safe; but, one way
  • will use explicit named locking and one will rely on the the
  • atomic integer class.
  • --->
  • <cffunction
  • name="incrementCounter"
  • access="public"
  • returntype="any"
  • output="false"
  • hint="I increment the given value with or without locking.">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="useLocking"
  • type="boolean"
  • required="true"
  • hint="I determine if locking should be used."
  • />
  •  
  • <!--- Check for locking. --->
  • <cfif arguments.useLocking>
  •  
  • <!---
  • Use an explicit lock around our standard integer
  • to make it safe.
  • --->
  • <cflock
  • name="counterIncrementLock"
  • type="exclusive"
  • timeout="2">
  •  
  • <!--- Increment and return standard value. --->
  • <cfreturn ++counter />
  •  
  • </cflock>
  •  
  • <cfelse>
  •  
  • <!--- Increment and return the atomic value. --->
  • <cfreturn atomicCounter.incrementAndGet() />
  •  
  • </cfif>
  • </cffunction>
  •  
  •  
  •  
  • <!---
  • Now, that we have are two ways of incrementing in place, let's
  • run some light-weight performance tests.
  • --->
  • <cfoutput>
  •  
  • <!--- Start with the standard name-locking. --->
  • <cftimer
  • type="outline"
  • label="Named-Locking">
  •  
  • <cfloop
  • index="i"
  • from="1"
  • to="10000"
  • step="1">
  •  
  • <!--- Increment value with named lock. --->
  • <cfset incrementCounter( true ) />
  •  
  • </cfloop>
  •  
  • Done (== #counter#)
  •  
  • </cftimer>
  •  
  • <!--- ------------------------------------------------- --->
  • <!--- ------------------------------------------------- --->
  •  
  • <!--- End with the atomic integer auto-safety. --->
  • <cftimer
  • type="outline"
  • label="Atomic-Integer">
  •  
  • <cfloop
  • index="i"
  • from="1"
  • to="10000"
  • step="1">
  •  
  • <!--- Increment atomic integer value. --->
  • <cfset incrementCounter( false ) />
  •  
  • </cfloop>
  •  
  • Done (== #atomicCounter#)
  •  
  • </cftimer>
  •  
  • </cfoutput>

As you can see in the above code, each test attempts 10,000 value increments; once on the standard int value using the ++ operator and ColdFusion's CFLock tag and, once on Java's AtomicInteger using the incrementAndGet() method. Despite the fact that the AtomicInteger has some special methods, notice that it extends the Number class and can be treated like a standard number if necessary (such as when I am outputting it at the end with hash signs).

I ran the above page a number of times and quick saw this trend emerging:

Named-Lock: 125-141ms

AtomicInteger: 62-78ms

Clearly, both of these methods used over 10,000 iterations are extremely fast! However, the AtomicInteger is about 100% faster than the use of named-locks. And, not only is it faster, but I find the incrementAndGet() method to be much more convenient than using the CFLock tag - especially when I only want to lock access to this one variable. The only trick is going to be remembering that you're dealing with a special kind of number.

This is very interesting stuff! Thanks to Dennis for directing me to a new and potentially useful Java class. I get the feeling that there is so much untapped Java goodness below the ColdFusion surface.


You Might Also Be Interested In:



Reader Comments

Jan 5, 2010 at 9:01 PM // reply »
38 Comments

Related question I had on Stackoverflow: http://stackoverflow.com/questions/1811406/thread-safe-sequential-number-generator-in-coldfusion

I'm now using AtomicInteger, glad you tested it out for me that it works well. :)


Jan 6, 2010 at 8:13 AM // reply »
10,640 Comments

@Henry,

Yeah, it seems cool. I am not sure how many times I will need to increment a value (in lieu of a database); but when I do, this will be a perfect solution.


Jan 6, 2010 at 11:19 PM // reply »
9 Comments

WOW! @Ben, I'm honored that you thought my comments worthy enough to inspire your own investigation of AtomicInteger and its performance.

You, in turn, have inspired me to take your experiment just a little bit further. You can read about what I did and the discoveries I made back on my own blog:

http://blog.bullamakanka.net/2010/01/thread-safety-of-integer-counters-in.html

Thanks again Ben!


Jan 9, 2010 at 9:46 PM // reply »
10,640 Comments

@Dennis,

It's all about good conversations and learning from each other :)


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Feb 12, 2012 at 3:37 AM
Learning ColdFusion 8: CFImage Part III - Watermarks And Transparency
Hi Ben, Just to ask currently it is placed bottom right corner, if i need to replace the same rendered image on the bottom left side or in the bottom center, how that can be calculated. bottom ce ... read »
Feb 11, 2012 at 9:29 PM
Use jQuery's SlideDown() With Fixed-Width Elements To Prevent Jumping
I can't say how glad I am that I found your post. Thank you very much. ... read »
Feb 10, 2012 at 7:21 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
Update! Instead of $(eval(options.insertAfter)).after(data['insertData']); I now use: var ajaxNode = document.createElement('span'); var parent = $(eval(options.insertAfter))[0].parentNode; ... read »
Feb 10, 2012 at 6:18 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
encountered this same, what I consider, jQuery bug last week. I'm building a site in which I load some content via AJAX. This content contains Linkedin share button placeholders which Linkedin API ne ... read »
Feb 10, 2012 at 11:30 AM
Cross-Origin Resource Sharing (CORS) AJAX Requests Between jQuery And Node.js
After you understand the concepts here, this is an awesome cheatsheet for enabling CORS in just about anything http://enable-cors.org/ ... read »
JM
Feb 10, 2012 at 9:10 AM
My Safari Browser SQLite Database Hello World Example
@Amy, Here is a very good tutorial on how to use JOIN: http://www.sqltutorial.org/sqljoin-innerjoin.aspx ... read »
Feb 10, 2012 at 4:42 AM
Building A Twitter-Inspired RESTful API Architecture In ColdFusion
This is great, very useful Ben. I spotted a small typo in the api.cgm listing: <cfthrow type="Unauthroized" /> Cheers Stefan ... read »
Feb 9, 2012 at 10:35 PM
CFDirectory Filtering Uses Pipe Character For Multiple Filters (Thanks Steve Withington)
I was wondering if there would be a filter you could apply so that you got everything but what you included in the filter. As in show me all docs that are not a .pdf. ... read »