Threading
Native threading constructs for simple asynchronous execution in BoxLang
BoxLang provides native threading constructs for simple asynchronous execution, allowing you to execute code in separate threads. Threads are independent streams of execution that can run simultaneously and asynchronously within a single request.
📋 Table of Contents
🎯 Overview
BoxLang threading allows you to:
✅ Execute code asynchronously in separate threads
✅ Continue request processing without waiting for threads
✅ Wait for threads to complete with join
✅ Pass data to threads via attributes
✅ Control thread priority and lifecycle
✅ Use virtual threads for lightweight concurrency (Java 21+)
Thread Execution Flow
🔀 When to Use Threading vs Async Programming
BoxLang provides two approaches to asynchronous programming:
Complexity
Simple, straightforward
Advanced, composable
Use Case
Fire-and-forget tasks
Chained async operations
Control
Basic (run, join, terminate)
Fine-grained (pipelines, executors)
Composition
Limited
Highly composable
Error Handling
Manual
Built-in exception handling
Return Values
Via thread scope
Direct return values
Best For
Simple parallel tasks
Complex async workflows
⚠️ A Fair Warning About Threading
Concurrency is Hard! Once you enter the world of multithreaded programming, be prepared for:
Thread Safety Issues - Shared data must be properly synchronized
Race Conditions - Multiple threads accessing shared resources simultaneously
Difficult Debugging -
writedump() + abortwon't work in threadsDeadlocks - Threads waiting indefinitely for resources
Memory Leaks - Data stored in thread scope persists after completion
Non-Deterministic Behavior - Execution order is unpredictable
Thread Safety Requirements
🐛 Thread Debugging
Traditional debugging techniques don't work in threads. Use these approaches:
Debugging Functions
println()
Write to console output
Console
writeOutput()
Write to output stream
Output
writedump( output="console" )
Dump complex objects
Console
writeLog()
Write to log files
Log file
Debugging Examples
Debug Output Destinations
Pro Tip: Use writeLog() with custom log files for production thread debugging. Console output only works in development environments.
📝 Thread Syntax
BoxLang provides multiple syntax options for creating threads:
Script Syntax
Template Syntax
Thread Attributes
name
string
Yes (for run)
Auto-generated
Unique identifier for the thread
action
string
No
run
Action to perform: run, join, sleep, terminate
priority
string
No
normal
Thread priority: high, low, normal
duration
integer
Conditional
-
Milliseconds to sleep (required for action="sleep")
timeout
integer
No
-
Milliseconds to wait for join before timeout
virtual
boolean
No
false
Use virtual threads (Java 21+)
* (custom)
any
No
-
Custom attributes passed to attributes scope
🎬 Thread Actions
Action: run (Create and Execute)
run (Create and Execute)Creates a new thread and executes the body asynchronously.
Action: join (Wait for Completion)
join (Wait for Completion)Waits for one or more threads to complete before continuing.
Join with Timeout:
Join All Threads:
Action: sleep (Pause Thread)
sleep (Pause Thread)Pauses the current thread for specified duration.
Action: terminate (Force Stop)
terminate (Force Stop)Forcibly terminates a running thread.
Warning: terminate forcibly stops a thread. This can leave resources in inconsistent states. Use with caution and prefer cooperative cancellation with threadInterrupt().
🏗️ Complete Thread Examples
Example 1: Fire-and-Forget Background Task
Example 2: Parallel Data Processing
Example 3: Thread with Priority
Example 4: Cooperative Thread Cancellation
🔭 Thread Scopes
BoxLang provides three scopes for managing thread data:
Scope Overview
Local
Thread only
Thread only
Thread duration
Internal thread variables
Thread
Thread only
All threads + main
Request duration
Share results with main thread
Attributes
None (read-only)
Thread only
Thread duration
Pass input data to thread
1. Thread Local Scope
Variables declared without scope prefix go into the thread's local scope - completely isolated from other threads.
2. Thread Scope (Shared Output)
The thread scope allows threads to write data that the main thread can read.
Writing to Thread Scope (Inside Thread)
Reading from Thread Scope (Outside Thread)
Complete Example
Memory Leak Warning: Thread scope data persists until the entire request completes, even after the thread finishes. Don't store large objects in thread scope unnecessarily!
Isolation: Thread scoped variables are only accessible within the request that created them. Other requests cannot access thread scope data.
3. Attributes Scope (Input Parameters)
Pass data into threads using attributes - any attribute not recognized as a built-in attribute becomes available in the attributes scope.
CRITICAL - Deep Copy Behavior: All attribute values are deep copied (duplicated) when passed to threads!
Simple values: Copied (safe)
Arrays/Structs: Entire collection duplicated (expensive)
Objects: Entire object graph duplicated (very expensive)
This ensures thread safety but can have significant performance implications!
Attribute Copy Example
Scope Access Patterns
🧪 Built-In Functions (BIFs)
BoxLang provides several BIFs for thread management:
Thread Management BIFs
threadNew()
Create thread from closure
threadNew( () => processData() )
threadJoin()
Wait for thread completion
threadJoin( "myThread", 5000 )
threadTerminate()
Force stop a thread
threadTerminate( "myThread" )
threadInterrupt()
Signal thread to stop
threadInterrupt( "myThread" )
isInThread()
Check if in thread context
if ( isInThread() ) { ... }
isThreadAlive()
Check if thread is running
if ( isThreadAlive( "myThread" ) ) { ... }
isThreadInterrupted()
Check interrupt status
if ( isThreadInterrupted() ) { break }
threadNew() - Functional Approach
threadNew() - Functional ApproachCreate threads from closures/lambdas instead of using thread construct:
With Parameters:
threadJoin() - Wait for Completion
threadJoin() - Wait for CompletionisInThread() - Context Detection
isInThread() - Context DetectionisThreadAlive() - Status Check
isThreadAlive() - Status CheckCooperative Cancellation Pattern
☁️ Virtual Threads (Java 21+)
BoxLang supports virtual threads (Project Loom) for lightweight, scalable concurrency.
What are Virtual Threads?
Virtual threads are:
Lightweight - Millions can run simultaneously
Efficient - Lower memory footprint than platform threads
Scalable - Perfect for I/O-bound workloads
Drop-in - Same API as regular threads
Using Virtual Threads
When to Use Virtual Threads
✅ Use Virtual Threads For:
I/O-bound operations (HTTP calls, database queries)
High concurrency scenarios (thousands of threads)
Blocking operations (file I/O, network)
❌ Don't Use Virtual Threads For:
CPU-intensive computations
Operations using
synchronizedblocks heavilyCode requiring thread-local storage
Virtual Thread Example
📊 Thread Metadata
Each thread automatically tracks metadata accessible via the thread scope:
Metadata Properties
name
string
Thread name
status
string
NOT_STARTED, RUNNING, COMPLETED, TERMINATED, INTERRUPTED
startTime
datetime
When thread started
endTime
datetime
When thread finished
elapsedTime
numeric
Execution time in milliseconds
priority
string
Thread priority (high, normal, low)
error
struct
Exception details if thread failed
output
string
Buffered output from thread
Accessing Metadata
Error Handling
✅ Best Practices
1. Always Name Your Threads
2. Use Join for Data Dependencies
3. Minimize Shared Data
4. Use Locks for Shared Resources
5. Always Handle Exceptions
6. Clean Up Resources
7. Use Timeouts for Joins
⚠️ Common Pitfalls
1. ❌ Race Conditions on Shared State
2. ❌ Forgetting Deep Copy of Attributes
3. ❌ Using writedump() + abort()
4. ❌ Ignoring Thread Safety
5. ❌ Thread Scope Memory Leaks
🔗 Next Steps: Advanced Async Programming
Native threading is great for simple parallelism, but for advanced async workflows, explore:
🚀 BoxFutures & Async Programming
For complex async operations, use the Asynchronous Programming framework:
runAsync()- Return-value based async with CompletableFuturesAsync Pipelines - Chain async operations with
then(),thenRun(),thenCompose()Parallel Collections -
array.parallel(),struct.parallel()Executor Services - Custom thread pools with
executorNew()Advanced Error Handling -
exceptionally(),whenComplete()Async Composition -
allOf(),anyOf(),race()
Recommendation: Use native threading for simple fire-and-forget tasks. Use BoxFutures for complex async workflows with return values, error handling, and composition.
Learn More:
📚 Related Documentation
Locking - Thread synchronization and locks
Variable Scopes - Understanding BoxLang scopes
Exception Handling - Error handling patterns
Asynchronous Programming - Advanced async with BoxFutures
Last updated
Was this helpful?
