Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at TechCrunch Disrupt (New York, NY) with: Aaron Foss

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

By Ben Nadel on
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.



Looking For A New Job?

100% of job board revenue is donated to Kiva. Loans that change livesFind out more »

Reader 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.

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
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.