Skip to main content
Ben Nadel at cf.Objective() 2017 (Washington, D.C.) with: Julie Dion and Catherine Neault
Ben Nadel at cf.Objective() 2017 (Washington, D.C.) with: Julie Dion Catherine Neault

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

By on
Tags:

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.

Want to use code from this post? Check out the license.

Reader Comments

15,674 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.

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel