Skip to content

Commit afd64e0

Browse files
docs: add complete README for Actor Model pattern also implemented changes iluwatar#3251
1 parent c0ecf29 commit afd64e0

File tree

8 files changed

+294
-66
lines changed

8 files changed

+294
-66
lines changed

Diff for: actor-model/README.md

+179-30
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,201 @@
1-
# Actor Model
1+
---
2+
title: "Actor Model Pattern in Java: Building Concurrent Systems with Elegance"
3+
shortTitle: Actor Model
4+
description: "Explore the Actor Model pattern in Java with real-world examples and practical implementation. Learn how to build scalable, message-driven systems using actors, messages, and asynchronous communication."
5+
category: Concurrency
6+
language: en
7+
tag:
8+
- Concurrency
9+
- Messaging
10+
- Isolation
11+
- Asynchronous
12+
- Distributed Systems
13+
- Actor Model
14+
---
215

3-
## Intent
16+
## Also Known As
417

5-
The Actor Model is a concurrency pattern that treats "actors" as the fundamental units of computation. Each actor has its own state and behavior and interacts with other actors exclusively through message passing.
18+
- Message-passing concurrency
19+
- Actor-based concurrency
620

7-
## Explanation
21+
---
822

9-
### Real-world Example
23+
## Intent of Actor Model Pattern
1024

11-
Imagine a team of people (actors) working in an office. They don’t share the same brain (memory), but instead communicate by passing notes (messages). Each person reads one note at a time and responds accordingly.
25+
The Actor Model pattern enables the construction of highly concurrent, distributed, and fault-tolerant systems by using isolated components (actors) that interact exclusively through asynchronous message passing.
1226

13-
### Problem
27+
---
1428

15-
Managing concurrent behavior in a safe and scalable way is difficult, especially with shared memory and race conditions.
29+
## Detailed Explanation of Actor Model Pattern with Real-World Examples
1630

17-
### Solution
31+
### 📦 Real-world Example
1832

19-
Encapsulate state and behavior within individual actors that communicate through asynchronous messages.
33+
Imagine a customer service system:
34+
- Each **customer support agent** is an **actor**.
35+
- Customers **send questions (messages)** to agents.
36+
- Each agent handles one request at a time and can **respond asynchronously** without interfering with other agents.
2037

21-
## Class Diagram
38+
---
2239

23-
![UML Diagram](etc/actor-model.png)
40+
### 🧠 In Plain Words
2441

25-
## Participants
42+
> "Actors are like independent workers that never share memory and only communicate through messages."
2643
27-
- **Actor**: Base class that defines a mailbox and handles incoming messages sequentially.
28-
- **Message**: Represents communication between actors.
29-
- **ActorSystem**: Creates and manages actors.
30-
- **PrinterActor**: Sample actor that prints incoming messages.
44+
---
3145

32-
## Applicability
46+
### 📖 Wikipedia Says
3347

34-
Use the Actor Model pattern when:
48+
> [Actor model](https://en.wikipedia.org/wiki/Actor_model) is a mathematical model of concurrent computation that treats "actors" as the universal primitives of concurrent computation.
3549
36-
- You need a simple and safe way to handle concurrency.
37-
- You want to avoid thread synchronization issues like race conditions and deadlocks.
38-
- You want each object to process messages independently.
50+
---
3951

40-
## Example
52+
### 🧹 Architecture Diagram
53+
54+
![UML Class Diagram](./etc/Actor_Model_UML_Class_Diagram.png)
55+
56+
---
57+
58+
## Programmatic Example of Actor Model Pattern in Java
59+
60+
### Actor.java
61+
62+
```java
63+
public abstract class Actor implements Runnable {
64+
65+
@Setter @Getter private String actorId;
66+
private final BlockingQueue<Message> mailbox = new LinkedBlockingQueue<>();
67+
private volatile boolean active = true;
68+
69+
70+
public void send(Message message) {
71+
mailbox.add(message);
72+
}
73+
74+
public void stop() {
75+
active = false;
76+
}
77+
78+
@Override
79+
public void run() {
80+
81+
}
82+
83+
protected abstract void onReceive(Message message);
84+
}
85+
86+
```
87+
88+
### Message.java
89+
90+
```java
91+
92+
@AllArgsConstructor
93+
@Getter
94+
@Setter
95+
public class Message {
96+
private final String content;
97+
private final String senderId;
98+
}
99+
```
100+
101+
### ActorSystem.java
102+
103+
```java
104+
public class ActorSystem {
105+
public void startActor(Actor actor) {
106+
String actorId = "actor-" + idCounter.incrementAndGet(); // Generate a new and unique ID
107+
actor.setActorId(actorId); // assign the actor it's ID
108+
actorRegister.put(actorId, actor); // Register and save the actor with it's ID
109+
executor.submit(actor); // Run the actor in a thread
110+
}
111+
public Actor getActorById(String actorId) {
112+
return actorRegister.get(actorId); // Find by Id
113+
}
114+
115+
public void shutdown() {
116+
executor.shutdownNow(); // Stop all threads
117+
}
118+
}
119+
```
120+
121+
### App.java
41122

42123
```java
43-
ActorSystem system = new ActorSystem();
44-
Actor printer = system.actorOf(new PrinterActor());
124+
public class App {
125+
public static void main(String[] args) {
126+
ActorSystem system = new ActorSystem();
127+
Actor srijan = new ExampleActor(system);
128+
Actor ansh = new ExampleActor2(system);
129+
130+
system.startActor(srijan);
131+
system.startActor(ansh);
132+
ansh.send(new Message("Hello ansh", srijan.getActorId()));
133+
srijan.send(new Message("Hello srijan!", ansh.getActorId()));
134+
135+
Thread.sleep(1000); // Give time for messages to process
136+
137+
srijan.stop(); // Stop the actor gracefully
138+
ansh.stop();
139+
system.shutdown(); // Stop the actor system
140+
}
141+
}
142+
```
143+
144+
---
145+
146+
## When to Use the Actor Model Pattern in Java
147+
148+
- When building **concurrent or distributed systems**
149+
- When you want **no shared mutable state**
150+
- When you need **asynchronous, message-driven communication**
151+
- When components should be **isolated and loosely coupled**
152+
153+
---
154+
155+
## Actor Model Pattern Java Tutorials
156+
157+
- [Baeldung – Akka with Java](https://www.baeldung.com/java-akka)
158+
- [Vaughn Vernon – Reactive Messaging Patterns](https://vaughnvernon.co/?p=1143)
159+
160+
---
161+
162+
## Real-World Applications of Actor Model Pattern in Java
163+
164+
- [Akka Framework](https://akka.io/)
165+
- [Erlang and Elixir concurrency](https://www.erlang.org/)
166+
- [Microsoft Orleans](https://learn.microsoft.com/en-us/dotnet/orleans/)
167+
- JVM-based game engines and simulators
168+
169+
---
170+
171+
## Benefits and Trade-offs of Actor Model Pattern
172+
173+
### ✅ Benefits
174+
- High concurrency support
175+
- Easy scaling across threads or machines
176+
- Fault isolation and recovery
177+
- Message ordering within actors
178+
179+
### ⚠️ Trade-offs
180+
- Harder to debug due to asynchronous behavior
181+
- Slight performance overhead due to message queues
182+
- More complex to design than simple method calls
183+
184+
---
185+
186+
## Related Java Design Patterns
187+
188+
- [Command Pattern](../command)
189+
- [Mediator Pattern](../mediator)
190+
- [Event-Driven Architecture](../event-driven-architecture)
191+
- [Observer Pattern](../observer)
192+
193+
---
45194

46-
printer.send(new Message("Hello Actor!", null));
47-
printer.send(new Message("Another message", null));
195+
## References and Credits
48196

49-
Thread.sleep(1000);
197+
- *Programming Erlang*, Joe Armstrong
198+
- *Reactive Design Patterns*, Roland Kuhn
199+
- *The Actor Model in 10 Minutes*, [InfoQ Article](https://www.infoq.com/articles/actor-model/)
200+
- [Akka Documentation](https://doc.akka.io/docs/akka/current/index.html)
50201

51-
((PrinterActor) printer).stop();
52-
system.shutdown();

Diff for: actor-model/pom.xml

+56-5
Original file line numberDiff line numberDiff line change
@@ -41,23 +41,74 @@
4141
<artifactId>actor-model</artifactId>
4242
<name>Actor Model</name>
4343

44+
<!-- Force unified JUnit version to avoid classpath mismatches -->
45+
<dependencyManagement>
46+
<dependencies>
47+
<dependency>
48+
<groupId>org.junit</groupId>
49+
<artifactId>junit-bom</artifactId>
50+
<version>5.11.0</version>
51+
<type>pom</type>
52+
<scope>import</scope>
53+
</dependency>
54+
</dependencies>
55+
</dependencyManagement>
56+
4457
<dependencies>
45-
<!-- JUnit 5 Jupiter API -->
4658
<dependency>
4759
<groupId>org.junit.jupiter</groupId>
4860
<artifactId>junit-jupiter-api</artifactId>
49-
<version>5.10.0</version>
5061
<scope>test</scope>
5162
</dependency>
52-
53-
<!-- JUnit 5 Jupiter Engine -->
5463
<dependency>
5564
<groupId>org.junit.jupiter</groupId>
5665
<artifactId>junit-jupiter-engine</artifactId>
57-
<version>5.10.0</version>
5866
<scope>test</scope>
5967
</dependency>
68+
<dependency>
69+
<groupId>org.junit.platform</groupId>
70+
<artifactId>junit-platform-launcher</artifactId>
71+
<scope>test</scope>
72+
</dependency>
73+
<dependency>
74+
<groupId>org.slf4j</groupId>
75+
<artifactId>slf4j-api</artifactId>
76+
</dependency>
77+
<dependency>
78+
<groupId>ch.qos.logback</groupId>
79+
<artifactId>logback-classic</artifactId>
80+
</dependency>
6081
</dependencies>
6182

83+
<build>
84+
<plugins>
85+
<!-- Assembly plugin for creating fat JARs -->
86+
<plugin>
87+
<groupId>org.apache.maven.plugins</groupId>
88+
<artifactId>maven-assembly-plugin</artifactId>
89+
<version>3.3.0</version>
90+
<configuration>
91+
<descriptorRefs>
92+
<descriptorRef>jar-with-dependencies</descriptorRef>
93+
</descriptorRefs>
94+
<archive>
95+
<manifest>
96+
<mainClass>com.iluwatar.actormodel.App</mainClass>
97+
</manifest>
98+
</archive>
99+
</configuration>
100+
<executions>
101+
<execution>
102+
<id>make-assembly</id>
103+
<phase>package</phase>
104+
<goals>
105+
<goal>single</goal>
106+
</goals>
107+
</execution>
108+
</executions>
109+
110+
</plugin>
111+
</plugins>
112+
</build>
62113

63114
</project>

Diff for: actor-model/src/main/java/com/iluwatar/actormodel/App.java

+24-3
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,38 @@
2222
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2323
* THE SOFTWARE.
2424
*/
25+
26+
/**
27+
* The Actor Model is a design pattern used to handle concurrency in a safe, scalable, and
28+
* message-driven way.
29+
*
30+
* <p>In the Actor Model: - An **Actor** is an independent unit that has its own state and behavior.
31+
* - Actors **communicate only through messages** — they do not share memory. - An **ActorSystem**
32+
* is responsible for creating, starting, and managing the lifecycle of actors. - Messages are
33+
* delivered asynchronously, and each actor processes them one at a time.
34+
*
35+
* <p>💡 Key benefits: - No shared memory = no need for complex thread-safety - Easy to scale with
36+
* many actors - Suitable for highly concurrent or distributed systems
37+
*
38+
* <p>🔍 This example demonstrates the Actor Model: - `ActorSystem` starts two actors: `srijan` and
39+
* `ansh`. - `ExampleActor` and `ExampleActor2` extend the `Actor` class and override the
40+
* `onReceive()` method to handle messages. - Actors communicate using `send()` to pass `Message`
41+
* objects that include the message content and sender's ID. - The actors process messages
42+
* **asynchronously in separate threads**, and we allow a short delay (`Thread.sleep`) to let them
43+
* run. - The system is shut down gracefully at the end.
44+
*/
2545
package com.iluwatar.actormodel;
2646

2747
public class App {
2848
public static void main(String[] args) throws InterruptedException {
2949
ActorSystem system = new ActorSystem();
3050
Actor srijan = new ExampleActor(system);
31-
system.startActor(srijan);
3251
Actor ansh = new ExampleActor2(system);
52+
53+
system.startActor(srijan);
3354
system.startActor(ansh);
34-
ansh.send(new Message("Hello Srijan", srijan.getActorId()));
35-
srijan.send(new Message("Hello ansh!", srijan.getActorId()));
55+
ansh.send(new Message("Hello ansh", srijan.getActorId()));
56+
srijan.send(new Message("Hello srijan!", ansh.getActorId()));
3657

3758
Thread.sleep(1000); // Give time for messages to process
3859

Diff for: actor-model/src/main/java/com/iluwatar/actormodel/ExampleActor.java

+10-4
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,28 @@
2424
*/
2525
package com.iluwatar.actormodel;
2626

27-
import java.util.logging.Logger;
27+
import java.util.ArrayList;
28+
import java.util.List;
29+
import lombok.Getter;
30+
import lombok.extern.slf4j.Slf4j;
2831

32+
@Slf4j
2933
public class ExampleActor extends Actor {
3034
private final ActorSystem actorSystem;
35+
@Getter private final List<String> receivedMessages = new ArrayList<>();
3136

3237
public ExampleActor(ActorSystem actorSystem) {
3338
this.actorSystem = actorSystem;
3439
}
3540

36-
Logger logger = Logger.getLogger(getClass().getName());
41+
// Logger log = Logger.getLogger(getClass().getName());
3742

3843
@Override
3944
protected void onReceive(Message message) {
40-
logger.info("[" + getActorId() + "]" + "Received : " + message.getContent());
41-
45+
LOGGER.info(
46+
"[{}]Received : {} from : [{}]", getActorId(), message.getContent(), message.getSenderId());
4247
Actor sender = actorSystem.getActorById(message.getSenderId()); // sender actor id
48+
// Reply of the message
4349
if (sender != null && !message.getSenderId().equals(getActorId())) {
4450
sender.send(new Message("I got your message ", getActorId()));
4551
}

0 commit comments

Comments
 (0)