Cajun
A pluggable actor system written in java leveraging modern features from JDK21+
Install / Use
/learn @CajunSystems/CajunREADME
Cajun - Concurrency And Java UNlocked
<div style="text-align:center"> <p>Predictable concurrency for Java applications using the actor model</p> <p><em>Leveraging virtual threads and modern features from JDK21+</em></p> <img src="docs/logo.png" alt="Alt Text" style="width:50%; height:auto;"> </div>📚 Full Documentation | 🚀 Quick Start | 📦 Installation
Table of Contents
Getting Started
Core Concepts
- Understanding Actors
- Creating Your First Actors
- Actor ID Strategies
- Actor Communication
- Actor Lifecycle
Essential Features
Intermediate Topics
Advanced Features
Reference
What is Cajun?
Cajun (Concurrency And Java UNlocked) is a lightweight actor system for Java that makes concurrent programming simple and safe. Instead of managing threads, locks, and shared state yourself, you write simple actors that communicate through messages.
Why Actors?
Traditional concurrent programming is hard:
- 🔒 Managing locks and synchronization
- 🐛 Avoiding race conditions and deadlocks
- 🔍 Debugging concurrent issues
- 📊 Coordinating shared state
Actors make it simple:
- ✅ Each actor processes one message at a time
- ✅ No shared state = no race conditions
- ✅ Built-in error handling and recovery
- ✅ Easy to test and reason about
When Should You Use Cajun?
✅ Perfect for (Near-Zero Overhead):
- I/O-Heavy Applications: Microservices, web apps, REST APIs
- Performance: 0.02% overhead - actors perform identically to raw threads!
- Database calls, HTTP requests, file operations
- Event-Driven Systems: Kafka/RabbitMQ consumers, event processing
- Performance: 0.02% overhead for I/O-bound message processing
- Excellent for stream processing and event sourcing
- Stateful Services: User sessions, game entities, shopping carts
- Performance: 8% overhead but you get thread-safe state management
- Complex stateful logic that needs isolation
- Message-Driven Architectures: Workflows, sagas, orchestration
- Performance: < 1% overhead for realistic mixed workloads
- Systems requiring fault tolerance and supervision
⚠️ Consider alternatives for:
- Embarrassingly Parallel CPU Work: Matrix multiplication, data transformations
- Raw threads are 10x faster for pure parallel computation
- Use parallel streams or thread pools instead
- Simple Scatter-Gather: No state, just parallel work and collect results
- Threads are 38% faster for this specific pattern
- CompletableFuture composition is simpler
Key Insight: Cajun uses virtual threads, which excel at I/O-bound workloads (databases, networks, files). For typical microservices and web applications, actor overhead is negligible (< 1%) while providing superior architecture benefits.
How Cajun Works
Cajun uses the actor model to provide predictable concurrency:
- Message Passing: Actors communicate by sending messages (no shared state)
- Isolated State: Each actor owns its state privately
- Serial Processing: Messages are processed one at a time, in order
- No User-Level Locks: You write lock-free code - the actor model handles isolation
Built on Java 21+ Virtual Threads: Cajun leverages virtual threads for exceptional I/O performance. Each actor runs on a virtual thread, allowing you to create thousands of concurrent actors with minimal overhead.
Performance Profile (Benchmarked November 2025):
- I/O-Bound Workloads: 0.02% overhead - essentially identical to raw threads!
- Perfect for microservices, web applications, database operations
- Virtual threads "park" during I/O instead of blocking OS threads
- CPU-Bound Workloads: 8% overhead - excellent for stateful operations
- Acceptable trade-off for built-in state management and fault tolerance
- Mixed Workloads: < 1% overhead - ideal for real-world applications
- Typical request handling (DB + business logic + rendering)
Thread Pool Configuration: Virtual threads are the default and perform best across all tested scenarios. You can optionally configure different thread pools per actor, but benchmarks show virtual threads outperform fixed and work-stealing pools for actor workloads.
Note: While your application code doesn't use locks, the JVM and mailbox implementations may use locks internally. The key benefit is that you don't need to manage synchronization.
Key Benefits
- No User-Level Locks: Write concurrent code without explicit locks, synchronized blocks, or manual coordination - the actor model handles isolation
- Predictable Behavior: Deterministic message ordering makes systems easier to reason about and test
- Exceptional I/O Performance: 0.02% overhead for I/O-bound workloads - actors perform identically to raw threads for microservices and web apps
- Scalability: Easily scale from single-threaded to multi-threaded to distributed systems
- Virtual threads enable thousands of concurrent actors with minimal overhead
- Fault Tolerance: Built-in supervision strategies for handling failures gracefully
- Flexibility: Multiple programming styles (OO, functional, stateful) to match your needs
- Production-Ready Performance:
- I/O workloads: 0.02% overhead (negligible)
- CPU workloads: 8% overhead (excellent for state management)
- Mixed workloads: < 1% overhead (ideal for real applications)
- Virtual Thread Based: Built on Java 21+ virtual threads for efficient blocking I/O with simple, natural code
- Simple Defaults: All default configurations are optimal - no tuning required for 99% of use cases
Dedication: Cajun is inspired by Erlang OTP and the actor model, and is dedicated to the late Joe Armstrong from Ericsson, whose pioneering work on Erlang and the actor model has influenced a generation of concurrent programming systems. Additional inspiration comes from Akka/Pekko.
Quick Start (5 Minutes)
Get up and running with Cajun in just a few minutes!
Prerequisites
- Java 21+ (with --enable-preview flag)
Installation
Cajun is available on Maven Central. Add it to your project using Gradle:
dependencies {
implementation 'com.cajunsystems:cajun:0.4.0'
}
Or with Maven:
<dependency>
<groupId>com.cajunsystems</groupId>
<artifactId>cajun</artifactId>
<version>0.4.0</version>
</dependency>
Note: Since Cajun uses Java preview features, you need to enable preview features in your build:
Gradle:
tasks.withType(JavaCompile) {
options.compilerArgs.add('--enable-preview')
}
tasks.withType(JavaExec) {
jvmArgs += '--enable-preview'
}
tasks.withType(Test) {
jvmArgs += '--enable-preview'
}
Maven:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<compilerArgs>
<arg>--enable-preview</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<argLine>--enable-preview</argLine>
</configuration>
</plugin>
</plugins>
</build>
Your First Actor
Here's a complete, runnable example to get you started:
import com.cajunsystems.*;
import com.cajunsystems.handler.Handler;
public class HelloWorld {
// Define your message types with explicit replyTo
public record HelloMessage(String name, Pid r
