Code Locking
BoxLang provides powerful thread-safe locking mechanisms for synchronizing access to shared resources with named locks, scope locks, and full Java interop support.
Locking is essential for multi-threaded applications where multiple requests or threads access shared resources. BoxLang's locking system uses Java's ReentrantReadWriteLock internally, providing robust, high-performance synchronization with support for both exclusive (write) and readonly (read) locks.
📋 Table of Contents
🎯 Lock Basics
BoxLang provides the lock component/construct for thread-safe synchronization:
// Script syntax
lock name="mylock" timeout=10 {
// Synchronized code here
criticalOperation()
}
// Template syntax
<bx:lock name="mylock" timeout="10">
<!-- Synchronized code here -->
</bx:lock>
// CFML compatibility
<cflock name="mylock" timeout="10">
<!-- Synchronized code here -->
</cflock>When to Use Locks
Use locks when:
✅ Multiple threads access shared data
✅ Writing to shared variables (application, server, session scopes)
✅ Reading shared data that might be modified
✅ Ensuring atomic operations
✅ Preventing race conditions
✅ Coordinating access to external resources
Lock Flow Diagram
🔐 Lock Types
BoxLang supports two lock types based on Java's ReentrantReadWriteLock:
1. Exclusive Locks (Write Locks)
Exclusive locks allow only ONE thread to access the locked code at a time. Use for read/write operations on shared data.
Characteristics:
✅ Single-thread access only
✅ Blocks all other threads (both exclusive and readonly)
✅ Use for writing or modifying shared data
✅ First-come, first-served basis
2. Readonly Locks (Read Locks)
Readonly locks allow MULTIPLE threads to access the locked code simultaneously. Use for read-only operations on shared data.
Characteristics:
✅ Multiple concurrent readers allowed
✅ Blocked by exclusive locks
✅ Use for reading shared data
✅ Better performance for read-heavy workloads
Lock Type Comparison
Concurrent Access
❌ No (single thread)
✅ Yes (multiple threads)
Blocks Exclusive
✅ Yes
✅ Yes
Blocks Readonly
✅ Yes
❌ No
Use For
Writing/Modifying
Reading only
Performance
Lower throughput
Higher throughput
Default
✅ Yes
❌ No
Lock Type Interactions
📛 Named Locking
Named locks use a string identifier to coordinate access across the entire BoxLang server.
Basic Named Lock
Global Scope: Lock names are server-wide and shared across ALL applications running on the same BoxLang instance. Use unique, descriptive names to avoid conflicts between applications.
Naming Conventions
Use descriptive, namespaced lock names to avoid collisions:
Lock Name Characteristics
Case-Sensitive:
"MyLock"and"mylock"are different locksServer-Wide: Shared across all applications on the server
Dynamic: Can use variables/expressions in names
Must be Non-Empty: Empty strings not allowed
Named Lock Examples
Example 1: Cache Population
Example 2: Counter Increment
Example 3: Multiple Locks with Different Names
🎯 Scope Locking
Scope locks synchronize access to entire BoxLang scopes: application, server, session, request.
Scope Lock Syntax
How Scope Locks Work
Each scope has a unique internal lock name generated from the scope name and instance hash:
This ensures each scope instance (e.g., each session) has its own lock.
Available Scopes
application
Per application
Application-wide shared data
server
Per server
Server-wide shared data
session
Per session
User-specific session data
request
Per request
Request-scoped coordination
Scope Lock Examples
Example 1: Application Counter
Example 2: Session Data Update
Example 3: Server-Wide Configuration
Performance Warning: Scope locks are coarse-grained - they lock the ENTIRE scope. This can become a performance bottleneck in high-traffic applications. Prefer named locks with specific names for fine-grained control.
Scope Lock vs Named Lock
⚙️ Lock Attributes
Complete reference for all lock component attributes:
name
string
⚠️ *
-
Lock name (server-wide unique identifier). Cannot be empty.
scope
string
⚠️ *
-
Scope to lock (application, server, session, request)
timeout
integer
✅ Yes
-
Maximum seconds to wait for lock. 0 = wait forever.
type
string
❌ No
"exclusive"
Lock type: "exclusive" or "readonly"
throwOnTimeout
boolean
❌ No
true
Throw LockException on timeout?
* Mutually Exclusive: Must provide either name OR scope, but not both.
Attribute Details
name - Lock Name
name - Lock NameServer-wide unique identifier
Case-sensitive
Can use expressions:
name="lock-#userId#"Cannot be empty string
Mutually exclusive with
scope
scope - Scope Name
scope - Scope NameValues:
application,server,session,requestLocks entire scope
Mutually exclusive with
name
timeout - Wait Time
timeout - Wait TimePositive integer: Wait N seconds for lock
Zero (0): Wait forever (until lock acquired)
If lock not acquired within timeout, behavior depends on
throwOnTimeout
type - Lock Type
type - Lock Type"exclusive"(default): Single-thread access (write lock)"readonly": Multi-thread access (read lock)Case-insensitive
throwOnTimeout - Timeout Behavior
throwOnTimeout - Timeout Behaviortrue(default): ThrowsLockExceptionif timeout reachedfalse: Skips lock body silently and continues execution
Attribute Examples
🔄 Double-Check Locking Pattern
The double-check locking pattern prevents race conditions where multiple threads check a condition, then compete to initialize a resource.
The Problem: Race Condition
Problem: If 10 threads are waiting at the lock, all 10 will execute the expensive operation!
The Solution: Double-Check Pattern
Double-Check Pattern Diagram
Real-World Examples
Example 1: Cache Population
Example 2: Singleton Initialization
Example 3: Application Initialization
Why Double-Check Works
First Check (outside lock): Fast path - avoids lock overhead when value exists
Second Check (inside lock): Prevents race condition - ensures only one thread initializes
Lock Protection: Guarantees atomic initialization
Best Practice: Always use double-check locking when initializing expensive resources that multiple threads might try to create simultaneously!
⚠️ Deadlock Prevention
A deadlock occurs when threads are waiting for locks held by each other, creating a cycle that cannot be broken.
Deadlock Example
Deadlock Diagram
Deadlock Prevention Strategies
1. Consistent Lock Ordering
Always acquire locks in the same order across all code:
2. Use Minimal Timeout
Always set reasonable timeouts so locks auto-release:
3. Avoid Nested Locks
Simplest solution - don't nest locks:
4. Use Lock Hierarchies
Establish a hierarchy and always lock from top to bottom:
Deadlock Recovery
BoxLang's locks automatically release on:
✅ Timeout: Lock acquisition times out
✅ Exception: Thread throws exception
✅ Thread Termination: Thread ends abnormally
Deadlock Best Practices
✅ Always use timeouts - Never use timeout=0 in production ✅ Consistent ordering - Document and enforce lock order ✅ Minimize lock scope - Lock smallest code section possible ✅ Avoid nesting - Use single locks when possible ✅ Use named locks - More precise than scope locks ✅ Log lock acquisitions - Track lock usage patterns ✅ Monitor lock times - Identify bottlenecks
Critical: BoxLang uses Java's ReentrantReadWriteLock internally, which automatically releases locks on timeout or thread termination, preventing infinite deadlocks. However, large timeouts can still block threads and reduce throughput!
☕ Advanced: Java Interop Locking
BoxLang's full Java interop allows you to use native Java synchronization mechanisms directly for advanced locking scenarios.
Using Java ReentrantLock
Java's ReentrantLock provides explicit lock/unlock control:
Using Java ReentrantReadWriteLock
BoxLang's lock component uses this internally:
Using Java Synchronized Blocks
Java's synchronized keyword via BoxLang:
Using Java Semaphores
Control access with permits:
Using Java CountDownLatch
Wait for multiple threads to complete:
Using Java CyclicBarrier
Synchronize threads at a barrier point:
Using Java Atomic Variables
Lock-free atomic operations:
Using Java ConcurrentHashMap
Thread-safe map without explicit locks:
Advanced Pattern: Custom Lock Manager
Comparison: BoxLang vs Java Locking
Feature
BoxLang lock
Java Locks
Use When
Syntax
Simple, declarative
Explicit lock/unlock
BoxLang: Simplicity
Auto-release
✅ Automatic
❌ Manual finally
BoxLang: Safety
Timeout
✅ Built-in
Manual
BoxLang: Deadlock prevention
Read/Write
✅ Built-in types
Manual handling
BoxLang: Simplicity
Advanced Control
❌ Limited
✅ Full control
Java: Fine-grained
Lock-free
❌ No
✅ Atomics
Java: Performance
Semaphores
❌ No
✅ Yes
Java: Permits
Barriers
❌ No
✅ Yes
Java: Coordination
Best Practice: Use BoxLang's lock component for most cases. It's safer (auto-releases), simpler (declarative), and has built-in timeouts. Use Java locks only when you need advanced features like semaphores, barriers, or lock-free atomic operations.
Java Interop Examples
Example 1: Rate Limiting with Semaphore
Example 2: Atomic Counter
Example 3: Thread-Safe Cache
💡 Best Practices
1. Use Minimum Timeouts
2. Prefer Named Locks Over Scope Locks
3. Always Use Double-Check Pattern
4. Use Descriptive Lock Names
5. Handle Timeouts Appropriately
6. Use Readonly Locks for Read Operations
7. Keep Lock Scope Minimal
8. Document Lock Dependencies
9. Monitor Lock Performance
10. Use Java Locks for Advanced Scenarios
📋 Summary
BoxLang locking provides powerful thread synchronization:
✅ Two Lock Types - Exclusive (write) and Readonly (read)
✅ Named Locks - Server-wide locks by name
✅ Scope Locks - Lock entire BoxLang scopes
✅ Automatic Release - Locks release on timeout/exception
✅ Timeout Control - Prevent infinite deadlocks
✅ ReentrantReadWriteLock - High-performance Java locks internally
✅ Java Interop - Full access to Java concurrency APIs
✅ Deadlock Prevention - Built-in timeout mechanisms
Pro Tip: Use named locks with double-check pattern for most scenarios. Reserve scope locks for coarse-grained operations, and use Java locks only when you need advanced features like semaphores or lock-free atomics!
🔗 Related Documentation
Threading - Concurrent execution
Variable Scopes - Understanding BoxLang scopes
Exception Management - Handling LockException
Java Integration - Java interop details
Java Concurrency Tutorial - Oracle's Java synchronization guide
Last updated
Was this helpful?
