-
Notifications
You must be signed in to change notification settings - Fork 9
Home
You've read the README so you know CFConcurrent's purpose; now you want to see code. This wiki's focus is on providing usage documentation for CFConcurrent.
The Java Concurrency Framework ( tutorial | javadocs ) provides thread-safe datatypes, concurrency abstractions such as locks/latches/mutexes, and generic "Executor" services. CFConcurrent aims to ease construction of these Java objects, but most importantly it simplifies usage of the Executor services. CFConcurrent is not a "wrapper" that shields you from scary Java; rather, it lubes some of the Java -- ColdFusion friction and hopes to help you achieve safe, correct, perhaps even joyful programming with respect to concurrency. Think of the Java Concurrency Framework as CFThread, all grown up and ready for real-world usage.
Executor Services revolve around the concept of Tasks. These are typically single units of work, implementing either the Callable
or Runnable
interface. For your purposes, Tasks are ColdFusion Components (CFCs) that either provide a call()
or run()
method. We'll discuss Callable vs. Runnable in more detail on the Tasks page. For now, simply know that nearly all of the work you do when working with CFConcurrent will be writing code just as you always have, and it'll be within the context of a CFC where the work is done in a method named call()
. Examples will clarify.
- OMG I Cannot Wait
- Begin with the End in Mind
- Tasks
- ExecutorService
- ExecutorCompletionService
- ScheduledThreadPoolExecutor
- ForkJoinPool
- Determining Configuration Options
- Getting the Java Objects from the Services
- Using the Object Factory
-
On CF9, entityLoad() and entityNew() do not work inside of Tasks. entitySave() on an entity passed into the Task at time of creation does work. Thus, if you need to load or create new persistent entities, do so prior to constructing the object and pass them into the Task's init() method.
-
On CF10, your tasks might throw an "ORM is not configured for this application" error. The workaround is simple, if arcane. You'll tell ColdFusion the name of your application:
function call(){
try{
var fc = createObject("java", "coldfusion.filter.FusionContext").init();
fc.getCurrent().setApplicationName("cfconcurrent_ormInExecutor");
results.fetched = entityLoadByPk("Artist", results.id );
} catch( any e ){
...
}
...
}
The important lines are the two after the try{
, wherein you get a handle on the current FusionContext
and give it the same name as this.name
in your Application.cfc
- On CF10, when using a
ScheduledThreadPoolExecutor
to run Tasks that use WebSockets, you'll get errors from CF that the channel does not exist. To solve this, use the exact same fix as you use above for ORM -- set the ApplicationName into the FusionContext
Good question. The JCF is not without its limitations. In fact, the JCF is a veteran, with its roots dating back to 1998 in Doug Lea's util.concurrent library. It became an official JDK library with the launch of Java5 in 2004, as java.util.concurrent. For context, CFMX 6.1 was also introduced in 2004. Some might argue that the JCF is primitive technology, and that superior, more modern alternatives exist.
This may be true.
However, I believe that the JCF is the best choice for most ColdFusion applications that require a rock-solid solution for writing correct concurrent programs. It requires zero extra dependencies. You write in 100% CFML, so it is likely to be easier to maintain by the largest number of people on the team. And it is damn good.
If I were writing a 1-billion-message-per-second message queue, I would not use the JCF. Nor would I use ColdFusion.
If I were writing a ColdFusion application that could benefit from concurrency, I would use the JCF (via CFConcurrent).
CFConcurrent's API Docs live here
You will also be interested in the JCF tutorial and javadocs