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 RIA Unleashed (Nov. 2010) with: Carol Loffelmann

Using AtomicInteger To Create Uniquely Named CFThreads In ColdFusion

By Ben Nadel on
Tags: ColdFusion

When you use CFThread to run code asynchronously in ColdFusion, all threads in a given request need to be uniquely named. This is (theoretically) because all threads in a single request can be accessed, by name, using the "cfthread" scope, regardless of where in the codebase they were spawned. Failure to provide a unique name will precipitate the following ColdFusion error:

Attribute validation error for the cfthread tag. Thread with name XYZ could not be created. Thread names must be unique within a page.

As I've started to use CFThread inside of ColdFusion components, I developed a habit of generating these unique thread names using a combination of the parent method's name and a unique index. And, in order to generate this unique index, I've been relying on Java's AtomicInteger. The AtomicInteger is great because it provides a fast way to increment values in a thread-safe manner without having to rely on (relatively slow) named-locking.

In order to keep things as simple as possible, I usually factor out the thread-name generation into its own private method. To see what I mean, take a look at this sample ColdFusion component:

  • <!--- NOTE: CFSCRIPT tags added for Gist color-coding only. --->
  • <cfscript>
  •  
  • component
  • output = false
  • hint = "I do something asynchronously using CFThread."
  • {
  •  
  •  
  • // I return the initialized component.
  • any function init() {
  •  
  • // The atomic integer gives us an easy way to create a unique
  • // number in a thread-safe way without named-locking.
  • threadIndex = createObject( "java", "java.util.concurrent.atomic.AtomicInteger" ).init();
  •  
  • return( this );
  •  
  • }
  •  
  •  
  • // ---
  • // PUBLIC METHODS.
  • // ---
  •  
  •  
  • // I do something in an asynchronous manner.
  • void function doSomethingAsync( required numeric id ) {
  •  
  • thread
  • action = "run"
  • name = getUniqueThreadName( "doSomethingAsync" )
  • id = id
  • {
  •  
  •  
  • // ... Async code would go here ...
  • writeOutput( "Thread content for #id#." );
  •  
  •  
  • }
  •  
  • }
  •  
  •  
  • // ---
  • // PRIVATE METHODS.
  • // ---
  •  
  •  
  • // I create a unique thread name based on the given calling method.
  • private string function getUniqueThreadName( required string methodName ) {
  •  
  • var newIndex = threadIndex.incrementAndGet();
  •  
  • return( "Service-#methodName#-#newIndex#" );
  •  
  • }
  •  
  •  
  • }
  •  
  • </cfscript>

As you can see, each CFThread name is encapsulated behind a call to the getUniqueThreadName() method. And, each thread name is tied to both the name of the ColdFusion component and to the name of the method that is spawning the thread. I have found that this association makes the error logs much easier to read!




Reader Comments

for thread names i have a small cfm file i include in any component (or cfm) where i need thread access. It has a very simple method for generating a thread name. (along with several other thread assisting methods)

  • <cfscript>
  • private string function newThreadName(string prefix="")
  • {
  • return rereplace("#arguments.prefix##createUUID()#","[-_\.]","","all");
  • }
  • </cfscript>

Reply to this Comment

Wouldn't a simple createUUID() suffice? That's what I use when creating threads. Am I missing something important that could break my code?

Reply to this Comment

@Ralph,

It's funny, there are things that I like using UUID's for; and there are things that I don't. And I can't explain what the difference is - just a random gut-feeling at the time of code.

I think maybe the reason I don't use the UUID is because the uniqueness of the thread name does not have to be persisted in any way; or, be unique across users. I think I tend to use UUIDs when uniqueness has a higher, cross-cutting constraint.

That said, a UUID would definitely work :)

Reply to this Comment

The reason i didn't use a simple createUUID() was the extra characters seemed to be causing an error in my thread names. Not sure why.

The reason I use a prefix on the name is so that when i get an error and it logs to the console that there was an error in a thread I can tell which one. If they were straight uuids I wouldn't know where in the code to look for the failure. (I use a LOT of threads in a LARGE application.)

Reply to this Comment

@Tom,

Definitely - the prefixing is a must to make debugging easier. Since CFThread happens async, you don't see the errors in the main page requests. Digging through rows of UUIDs (only) in the error logs would drive me bananas :D

Reply to this Comment

Hi Ben
Interesting technique, but I gotta say I'm with Ralph on this one. Your approach seems to be a lot of unnecessary work for something that basically just needs a unique ID. And that's what UUIDs are for.

Still, obviously, I get that people have their own vagaries and preferences in how they like to approach things, so all good. And it's good to have options for these things :-)

--
Adam

Reply to this Comment

@Adam,

I will completely admit that my opposition to createUUID() is 100% emotional :) I think a long time ago, someone told me that creating UUIDs was "slow", and it probably just painted it in a bad light going forward.

The good news is that since it's encapsulated behind the getUniqueThreadName(), it could easily be swapped out for anything that can create uniqueness.

I still do like the idea of creating the thread name within a function since it hides the other cruff that (such at the component name) that goes into the thread name. In a case like this, where there's only one thread, it's not such a big deal; but I have some components in which all the methods (or many of them) spawn threads - and, having the unique name generation "hidden" makes the code easier to read (IMO).

Reply to this Comment

Hi Ben
I totally get where you're coming from with the "emotional" side of things. We've all got idiosyncrasies in our coding.

UUIDs certainly did used to be slow to create, although I think it only really became obvious under large load (the underlying java method was synchronised). And using up threads with CFTHREAD is probably gonna bite you sooner than generating UUIDs would ;-) The UUID performance issue has been resolved now (don't remember which version of CF or Java it was, but it was a coupla years back now).

And, yeah, detail-hiding like you're suggesting via a function is good practice / consideration.

Cheers.

--
Adam

Reply to this Comment

I'm quite new to multi threading in cold fusion. I'm always looking for ways to make things faster, but don't see a lot of scope for them in my apps. Ben, would you mind giving a couple of vague examples of components where you think heavy use of threads are important to you?

Reply to this Comment

@Tim,

I tend to use CFThread inside of a component if that component's purpose is to communicate with a 3rd party API over CFHTTP. For example, at InVision, we make use of the http://pusher.com webSockets as a service API. This needs to be invoked after various user-based events in the system. But, we do NOT want to block the user's response waiting for the 3rd party API to finish; so, we'll end up initiating the CFHTTP request inside an async thread.

We also do a lot of image processing inside of CFThread, again, so we don't block the user's response while doing things that the user doesn't necessarily need to wait for.

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.