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.




Reader Comments

Jan 5, 2010 at 9:01 PM // reply »
42 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 »
11,314 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 »
11,314 Comments

@Dennis,

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


Mar 8, 2013 at 8:54 AM // reply »
8 Comments

Hi Ben
I just stumbled across the non-thread-safety of the ++ operator today! There's a repro case on my blog:
http://adamcameroncoldfusion.blogspot.co.uk/2013/03/sean-prompts-me-to-look-at-coldfusion.html

--
Adam


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
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Jun 18, 2013 at 9:20 PM
Mapping AngularJS Routes Onto URL Parameters And Client-Side Events
I couldn't find examples of passing multiple arguments using the when() routing statement so figured out through trial and error that you can pass multiple arguments using the following format: .whe ... read »
Jun 18, 2013 at 3:39 PM
Experimenting With The Amazon Simple Storage Service (S3) API Using ColdFusion
Hi Ben, THANKS! While not bleeding edge, it is new to me & I like learning new things every day! ... read »
Jun 18, 2013 at 12:30 PM
Disabling Auto-Correct And Auto-Capitalize Features On iPhone Inputs
Also spellcheck="false" should be mentioned as part of html5 specs ... read »
Jun 18, 2013 at 8:40 AM
Using Named Functions Within Self-Executing Function Blocks In Javascript
Hi Ben, you forgot to mention the most important thing for named self-executing functions - they can be referenced by name ONLY inside their execution context (which is parens in this case), it mean ... read »
dee
Jun 18, 2013 at 7:01 AM
My Safari Browser SQLite Database Hello World Example
hai ben, this program is really good i could understand the concept but i dint know how to save it and how to open it as you have done in the video can u give that details pls ... read »
Jun 18, 2013 at 6:04 AM
Clearing Inline CSS Properties With jQuery
Thanks a lot for for post! It helped me a lot... after being stuck since 24 hrs.. found solution from your post. Thanks again! ... read »
Jun 18, 2013 at 2:31 AM
SOTR 2013 - The Best Conference I Never Went To
I keep watching it, should keep me happily distracted until SotR14 ;) ... read »
Jun 17, 2013 at 9:45 PM
What If All User Interface (UI) Data Came In Reports?
@Jonah, As I was reading what you wrote, it occurred to me that maybe I do something similar to that in some of my client-side code. In an application I'm working on, there are a bunch of unrelated ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools