# Complete Guide to Threading in Lucee



# Complete Guide to Threading in Lucee

Threads allow you to execute code in parallel, improving performance for tasks like database queries, HTTP requests, or any long-running operations.

Lucee offers several approaches, from simple high-level functions to full manual control:

1. **Collection Parallel Processing** - Simplest approach using `.each()` with parallel flag
2. **Function Listeners** - Modern async syntax for function calls (Lucee 6.1+)
3. **Basic Thread Blocks** - Simple cfthread usage for fire-and-forget operations
4. **Advanced Thread Management** - Full control with thread joining, monitoring, and coordination

## Collection Parallel Processing

The simplest way to execute code in parallel. Use `.each()` with the parallel flag and thread management is automatic.

### Parallel Array Processing

```javascript
// Process array items in parallel
items = ["item1", "item2", "item3", "item4", "item5"];
items.each(
    function(value, index) {
        // Simulate some work
        sleep(1000);
        systemOutput("Processed: #value# at #now()#", true);
    },
    true, // parallel execution
    3     // maxThreads: limit to 3 concurrent threads
);
dump("All items processed");
```

### Large Dataset with Thread Control

```javascript
// Process large dataset with controlled thread count
largeDataset = [];
loop from=1 to=100 index="i" {
    arrayAppend(largeDataset, "task_#i#");
}

largeDataset.each(
    function(task, index) {
        sleep(100);
        systemOutput("Completed: #task#", true);
    },
    true, // parallel execution
    10    // maxThreads: prevent system overload
);
dump("100 tasks completed with max 10 threads");
```

### Parallel Struct Processing

```javascript
// Process struct values in parallel with thread limit
userData = {
    "user1": "john@example.com",
    "user2": "jane@example.com", 
    "user3": "bob@example.com",
    "user4": "alice@example.com",
    "user5": "charlie@example.com"
};

userData.each(
    function(email, userId) {
        // Simulate sending email
        sleep(500);
        systemOutput("Email sent to #email# for user #userId#", true);
    },
    true, // parallel execution
    2     // maxThreads: process max 2 emails simultaneously
);
```

### Parallel Query Processing

```javascript
// Process query rows in parallel
users = query(
    'id': [1, 2, 3, 4, 5, 6, 7, 8],
    'name': ['John', 'Jane', 'Bob', 'Alice', 'Charlie', 'David', 'Eve', 'Frank'],
    'email': ['john@test.com', 'jane@test.com', 'bob@test.com', 'alice@test.com', 
              'charlie@test.com', 'david@test.com', 'eve@test.com', 'frank@test.com']
);

users.each(
    function(row, rowNumber) {
        // Process each user record
        sleep(200);
        systemOutput("Processed user: #row.name# (#row.email#)", true);
    },
    true, // parallel execution
    4     // maxThreads: process max 4 users concurrently
);
```

### Thread Limit Control

Collection functions (`.each()`, `.every()`, `.filter()`, `.map()`, `.some()`) all support `maxThreads`:

```javascript
// Syntax: collection.function(function, parallel, maxThreads)
// Default maxThreads = 20 when parallel = true
tasks = [];
loop from=1 to=50 index="i" {
    arrayAppend(tasks, "heavy_task_#i#");
}

tasks.each(
    function(task) {
        // CPU/memory intensive operation
        sleep(randRange(100, 500));
        systemOutput("Completed: #task#", true);
    },
    true, // parallel = true
    5     // maxThreads = 5 (overrides default of 20)
);

// Without maxThreads limit, this would use default of 20 threads!
// With maxThreads=5, only 5 threads run at once, others queue
```

### Parallel Functions

Arrays, structs, and queries support parallel execution:

- **`.each()`** - Execute code for every element (side effects, logging, processing)
- **`.filter()`** - Create new collection with elements matching criteria
- **`.map()`** - Transform every element and create new collection
- **`.every()`** - Test if all elements meet a condition (returns boolean)
- **`.some()`** - Test if any element meets a condition (returns boolean)

```javascript
// Array processing with .each()
items = ["item1", "item2", "item3", "item4", "item5"];
items.each(
    function(value, index, array) {
        sleep(200); // Simulate work
        systemOutput("Processed: #value# at index #index#", true);
    },
    true, // parallel
    3     // maxThreads
);

// Struct processing with .each()
userData = {
    "john": "john@example.com",
    "jane": "jane@example.com", 
    "bob": "bob@example.com",
    "alice": "alice@example.com"
};

userData.each(
    function(key, value, struct) {
        sleep(300); // Simulate email sending
        systemOutput("Email sent to #value# for user #key#", true);
    },
    true, // parallel
    2     // maxThreads
);

// Query processing with .each()
employees = query(
    'id': [1, 2, 3, 4],
    'name': ['John', 'Jane', 'Bob', 'Alice'],
    'department': ['IT', 'HR', 'Finance', 'Marketing']
);

employees.each(
    function(row, rowNumber, query) {
        sleep(150); // Simulate processing
        systemOutput("Processed employee: #row.name# in #row.department#", true);
    },
    true, // parallel
    2     // maxThreads
);
```

**Parameters:**

- `parallel` (boolean) - Enable parallel execution
- `maxThreads` (number, optional) - Maximum concurrent threads (alias: `maxThreadCount`)
- When `parallel=false`, `maxThreads` is ignored

## Function Listeners (Lucee 6.1+)

Modern promise-like syntax for async execution. See the [Function Listeners](function-listeners.md) recipe for full details.

### Simple Async Function Execution

```javascript
function fetchUserData(userId) {
    sleep(1000);
    return {"id": userId, "name": "User #userId#"};
}

// Execute function asynchronously with listener
fetchUserData(123):function(result, error) {
    request.userData = result;
};

dump("Function called asynchronously");
```

### Joining Function Listener Threads

```javascript
function processData(data) {
    sleep(1000);
    return data.len();
}

// Get thread name for joining
threadName = processData([1,2,3,4,5]):function(result, error) {
    thread.result = result;
};

// Do other work...
dump("Processing started");

// Wait for completion
threadJoin(threadName);
dump("Result: #cfthread[threadName].result#");
```

### Error Handling with Function Listeners

```javascript
function riskyOperation() {
    if (randRange(1,2) == 1) {
        throw "Random failure occurred!";
    }
    return "Success!";
}

riskyOperation():{
    onSuccess: function(result) {
        systemOutput("Operation succeeded: #result#", true);
    },
    onFail: function(error) {
        systemOutput("Operation failed: #error.message#", true);
    }
};
```

## Basic Thread Blocks

For fire-and-forget operations or when you need more control than collection processing.

### Fire-and-Forget Operations

```javascript
function logActivity(action) {
    thread {
        // This runs in background - doesn't block main execution
        sleep(500); // Simulate slow logging operation
        systemOutput("Logged: #action# at #now()#", true);
    }
}

start = getTickCount();
logActivity("User login");
logActivity("Page view");
logActivity("Button click");
dump("Main execution completed in #getTickCount()-start#ms");
// Logging continues in background
```

### Background Data Processing

```javascript
function processInBackground(data) {
    thread {
        // Heavy processing that shouldn't block the user
        sleep(3000);
        thread.result = "Processed #data.len()# items";
        thread.completedAt = now();
    }
}

userData = ["item1", "item2", "item3"];
processInBackground(userData);
dump("Processing started in background");
```

## Advanced Thread Management

Explicit thread management with joining, monitoring, and coordination.

### Multiple Coordinated Threads

```javascript
function fetchDataFromSource(sourceName, delay) {
    thread name="fetch_#sourceName#" {
        thread.startTime = now();
        sleep(delay);
        thread.data = "Data from #sourceName#";
        thread.endTime = now();
        thread.duration = dateDiff("s", thread.startTime, thread.endTime);
    }
}

start = getTickCount();

// Start multiple data fetching operations
fetchDataFromSource("database", 1000);
fetchDataFromSource("api", 1500);
fetchDataFromSource("cache", 500);
fetchDataFromSource("file", 800);

// Show all threads status before joining
dump(var: cfthread, label: "Threads Status Before Join");

// Wait for all threads to complete
thread action="join" name=cfthread.keyList();

// Show results
dump(var: cfthread, label: "All Threads Completed");
dump("Total execution time: #getTickCount()-start#ms");
```

### Thread Pool Management

```javascript
function processWorkItem(workId) {
    thread {
        thread.workId = workId;
        thread.startTime = now();
        
        // Simulate varying work complexity
        delay = randRange(500, 2000);
        sleep(delay);
        
        thread.result = "Work #workId# completed";
        thread.endTime = now();
    }
}

// Process multiple work items
workItems = [1,2,3,4,5,6,7,8,9,10];
start = getTickCount();

// Start all work items (Lucee manages thread pool automatically)
for (workId in workItems) {
    processWorkItem(workId);
}

// Monitor progress
activeThreads = cfthread.keyArray();
dump("Started #activeThreads.len()# threads");

// Wait for completion in batches
batchSize = 3;
completedCount = 0;

while (completedCount < workItems.len()) {
    sleep(100); // Check every 100ms
    
    for (threadName in activeThreads) {
        if (cfthread[threadName].status == "COMPLETED") {
            completedCount++;
            dump("Thread #threadName# completed: #cfthread[threadName].result#");
            activeThreads.deleteAt(activeThreads.find(threadName));
        }
    }
}

dump("All work completed in #getTickCount()-start#ms");
```

### Thread Communication and Shared Data

```javascript
// Shared data structure for thread communication
request.sharedCounter = 0;
request.results = [];

function workerThread(threadId) {
    thread name="worker_#threadId#" {
        loop from=1 to=5 index="i" {
            // Simulate work
            sleep(randRange(100, 300));
            
            // Update shared counter (be careful with race conditions in real apps)
            request.sharedCounter++;
            
            // Add result
            arrayAppend(request.results, "Thread #threadId# completed task #i#");
        }
        thread.completed = true;
    }
}

// Start worker threads
loop from=1 to=3 index="i" {
    workerThread(i);
}

// Monitor progress
while (request.sharedCounter < 15) { // 3 threads × 5 tasks each
    dump("Progress: #request.sharedCounter#/15 tasks completed");
    sleep(200);
}

// Wait for all threads to finish
thread action="join" name="worker_1,worker_2,worker_3";

dump("Final results:");
dump(request.results);
dump("All threads completed");
```

## Best Practices

- **`.each()` with parallel flag** - simple collection processing
- **Function Listeners** - modern async function calls with result handling
- **Thread blocks** - fire-and-forget background operations
- **Advanced thread management** - when you need precise control

## Additional Resources

- [Function Listeners](function-listeners.md) - Complete guide to async function execution
- [Lucee Threads Video Tutorial](https://www.youtube.com/watch?v=oGUZRrcg9KE)

# Categories

[Threads](../categories/thread.md), [Core CFML Language](../categories/core.md)

# See Also

[ArrayEach()](../reference/functions/arrayeach.md), [ArrayMap()](../reference/functions/arraymap.md), [ArrayReduce()](../reference/functions/arrayreduce.md), [<cfthread>](../reference/tags/thread.md), [Thread Tasks](thread-task.md), [Virtual Threads](virtual-threads.md)