mirror of
https://github.com/tiennm99/java-design-patterns.git
synced 2026-08-16 14:23:05 +00:00
feat: Implement Actor Model pattern
* feat: Implement Actor Model pattern #3232 * feat: Implement Actor Model pattern #3232 * feat: update Actor Model implementation with multi-actor logic #3251 * feat: update Actor Model implementation with multi-actor logic and loose coupling #3251 * test: add unit test for actor model #3251 * test: add test for App.java to increase coverage * docs: add complete README for Actor Model pattern also implemented changes #3251
This commit is contained in:
@@ -0,0 +1,201 @@
|
|||||||
|
---
|
||||||
|
title: "Actor Model Pattern in Java: Building Concurrent Systems with Elegance"
|
||||||
|
shortTitle: Actor Model
|
||||||
|
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."
|
||||||
|
category: Concurrency
|
||||||
|
language: en
|
||||||
|
tag:
|
||||||
|
- Concurrency
|
||||||
|
- Messaging
|
||||||
|
- Isolation
|
||||||
|
- Asynchronous
|
||||||
|
- Distributed Systems
|
||||||
|
- Actor Model
|
||||||
|
---
|
||||||
|
|
||||||
|
## Also Known As
|
||||||
|
|
||||||
|
- Message-passing concurrency
|
||||||
|
- Actor-based concurrency
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Intent of Actor Model Pattern
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Detailed Explanation of Actor Model Pattern with Real-World Examples
|
||||||
|
|
||||||
|
### 📦 Real-world Example
|
||||||
|
|
||||||
|
Imagine a customer service system:
|
||||||
|
- Each **customer support agent** is an **actor**.
|
||||||
|
- Customers **send questions (messages)** to agents.
|
||||||
|
- Each agent handles one request at a time and can **respond asynchronously** without interfering with other agents.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🧠 In Plain Words
|
||||||
|
|
||||||
|
> "Actors are like independent workers that never share memory and only communicate through messages."
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 📖 Wikipedia Says
|
||||||
|
|
||||||
|
> [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.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🧹 Architecture Diagram
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Programmatic Example of Actor Model Pattern in Java
|
||||||
|
|
||||||
|
### Actor.java
|
||||||
|
|
||||||
|
```java
|
||||||
|
public abstract class Actor implements Runnable {
|
||||||
|
|
||||||
|
@Setter @Getter private String actorId;
|
||||||
|
private final BlockingQueue<Message> mailbox = new LinkedBlockingQueue<>();
|
||||||
|
private volatile boolean active = true;
|
||||||
|
|
||||||
|
|
||||||
|
public void send(Message message) {
|
||||||
|
mailbox.add(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void onReceive(Message message);
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Message.java
|
||||||
|
|
||||||
|
```java
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class Message {
|
||||||
|
private final String content;
|
||||||
|
private final String senderId;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### ActorSystem.java
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class ActorSystem {
|
||||||
|
public void startActor(Actor actor) {
|
||||||
|
String actorId = "actor-" + idCounter.incrementAndGet(); // Generate a new and unique ID
|
||||||
|
actor.setActorId(actorId); // assign the actor it's ID
|
||||||
|
actorRegister.put(actorId, actor); // Register and save the actor with it's ID
|
||||||
|
executor.submit(actor); // Run the actor in a thread
|
||||||
|
}
|
||||||
|
public Actor getActorById(String actorId) {
|
||||||
|
return actorRegister.get(actorId); // Find by Id
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown() {
|
||||||
|
executor.shutdownNow(); // Stop all threads
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### App.java
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class App {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
ActorSystem system = new ActorSystem();
|
||||||
|
Actor srijan = new ExampleActor(system);
|
||||||
|
Actor ansh = new ExampleActor2(system);
|
||||||
|
|
||||||
|
system.startActor(srijan);
|
||||||
|
system.startActor(ansh);
|
||||||
|
ansh.send(new Message("Hello ansh", srijan.getActorId()));
|
||||||
|
srijan.send(new Message("Hello srijan!", ansh.getActorId()));
|
||||||
|
|
||||||
|
Thread.sleep(1000); // Give time for messages to process
|
||||||
|
|
||||||
|
srijan.stop(); // Stop the actor gracefully
|
||||||
|
ansh.stop();
|
||||||
|
system.shutdown(); // Stop the actor system
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## When to Use the Actor Model Pattern in Java
|
||||||
|
|
||||||
|
- When building **concurrent or distributed systems**
|
||||||
|
- When you want **no shared mutable state**
|
||||||
|
- When you need **asynchronous, message-driven communication**
|
||||||
|
- When components should be **isolated and loosely coupled**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Actor Model Pattern Java Tutorials
|
||||||
|
|
||||||
|
- [Baeldung – Akka with Java](https://www.baeldung.com/java-akka)
|
||||||
|
- [Vaughn Vernon – Reactive Messaging Patterns](https://vaughnvernon.co/?p=1143)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Real-World Applications of Actor Model Pattern in Java
|
||||||
|
|
||||||
|
- [Akka Framework](https://akka.io/)
|
||||||
|
- [Erlang and Elixir concurrency](https://www.erlang.org/)
|
||||||
|
- [Microsoft Orleans](https://learn.microsoft.com/en-us/dotnet/orleans/)
|
||||||
|
- JVM-based game engines and simulators
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Benefits and Trade-offs of Actor Model Pattern
|
||||||
|
|
||||||
|
### ✅ Benefits
|
||||||
|
- High concurrency support
|
||||||
|
- Easy scaling across threads or machines
|
||||||
|
- Fault isolation and recovery
|
||||||
|
- Message ordering within actors
|
||||||
|
|
||||||
|
### ⚠️ Trade-offs
|
||||||
|
- Harder to debug due to asynchronous behavior
|
||||||
|
- Slight performance overhead due to message queues
|
||||||
|
- More complex to design than simple method calls
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Related Java Design Patterns
|
||||||
|
|
||||||
|
- [Command Pattern](../command)
|
||||||
|
- [Mediator Pattern](../mediator)
|
||||||
|
- [Event-Driven Architecture](../event-driven-architecture)
|
||||||
|
- [Observer Pattern](../observer)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## References and Credits
|
||||||
|
|
||||||
|
- *Programming Erlang*, Joe Armstrong
|
||||||
|
- *Reactive Design Patterns*, Roland Kuhn
|
||||||
|
- *The Actor Model in 10 Minutes*, [InfoQ Article](https://www.infoq.com/articles/actor-model/)
|
||||||
|
- [Akka Documentation](https://doc.akka.io/docs/akka/current/index.html)
|
||||||
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 46 KiB |
@@ -0,0 +1,35 @@
|
|||||||
|
@startuml actor-model
|
||||||
|
|
||||||
|
title Actor Model - UML Class Diagram
|
||||||
|
|
||||||
|
class ActorSystem {
|
||||||
|
+actorOf(actor: Actor): Actor
|
||||||
|
+shutdown(): void
|
||||||
|
}
|
||||||
|
|
||||||
|
class Actor {
|
||||||
|
-mailbox: BlockingQueue<Message>
|
||||||
|
-active: boolean
|
||||||
|
+send(message: Message): void
|
||||||
|
+stop(): void
|
||||||
|
+run(): void
|
||||||
|
#onReceive(message: Message): void
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExampleActor {
|
||||||
|
+onReceive(message: Message): void
|
||||||
|
}
|
||||||
|
|
||||||
|
class Message {
|
||||||
|
-content: String
|
||||||
|
-sender: Actor
|
||||||
|
+getContent(): String
|
||||||
|
+getSender(): Actor
|
||||||
|
}
|
||||||
|
|
||||||
|
ActorSystem --> Actor : creates
|
||||||
|
Actor <|-- ExampleActor : extends
|
||||||
|
Actor --> Message : processes
|
||||||
|
ExampleActor --> Message : uses
|
||||||
|
|
||||||
|
@enduml
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
||||||
|
|
||||||
|
The MIT License
|
||||||
|
Copyright © 2014-2022 Ilkka Seppälä
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
||||||
|
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.iluwatar</groupId>
|
||||||
|
<artifactId>java-design-patterns</artifactId>
|
||||||
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>actor-model</artifactId>
|
||||||
|
<name>Actor Model</name>
|
||||||
|
|
||||||
|
<!-- Force unified JUnit version to avoid classpath mismatches -->
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit</groupId>
|
||||||
|
<artifactId>junit-bom</artifactId>
|
||||||
|
<version>5.11.0</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.platform</groupId>
|
||||||
|
<artifactId>junit-platform-launcher</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<!-- Assembly plugin for creating fat JARs -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<version>3.3.0</version>
|
||||||
|
<configuration>
|
||||||
|
<descriptorRefs>
|
||||||
|
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||||
|
</descriptorRefs>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>com.iluwatar.actormodel.App</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>make-assembly</id>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>single</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
||||||
|
*
|
||||||
|
* The MIT License
|
||||||
|
* Copyright © 2014-2022 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.iluwatar.actormodel;
|
||||||
|
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
public abstract class Actor implements Runnable {
|
||||||
|
|
||||||
|
@Setter @Getter private String actorId;
|
||||||
|
private final BlockingQueue<Message> mailbox = new LinkedBlockingQueue<>();
|
||||||
|
private volatile boolean active =
|
||||||
|
true; // always read from main memory and written back to main memory,
|
||||||
|
|
||||||
|
// rather than being cached in a thread's local memory. To make it consistent to all Actors
|
||||||
|
|
||||||
|
public void send(Message message) {
|
||||||
|
mailbox.add(message); // Add message to queue
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
active = false; // Stop the actor loop
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (active) {
|
||||||
|
try {
|
||||||
|
Message message = mailbox.take(); // Wait for a message
|
||||||
|
onReceive(message); // Process it
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Child classes must define what to do with a message
|
||||||
|
protected abstract void onReceive(Message message);
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
||||||
|
*
|
||||||
|
* The MIT License
|
||||||
|
* Copyright © 2014-2022 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.iluwatar.actormodel;
|
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
public class ActorSystem {
|
||||||
|
private final ExecutorService executor = Executors.newCachedThreadPool();
|
||||||
|
private final ConcurrentHashMap<String, Actor> actorRegister = new ConcurrentHashMap<>();
|
||||||
|
private final AtomicInteger idCounter = new AtomicInteger(0);
|
||||||
|
|
||||||
|
public void startActor(Actor actor) {
|
||||||
|
String actorId = "actor-" + idCounter.incrementAndGet(); // Generate a new and unique ID
|
||||||
|
actor.setActorId(actorId); // assign the actor it's ID
|
||||||
|
actorRegister.put(actorId, actor); // Register and save the actor with it's ID
|
||||||
|
executor.submit(actor); // Run the actor in a thread
|
||||||
|
}
|
||||||
|
|
||||||
|
public Actor getActorById(String actorId) {
|
||||||
|
return actorRegister.get(actorId); // Find by Id
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown() {
|
||||||
|
executor.shutdownNow(); // Stop all threads
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
||||||
|
*
|
||||||
|
* The MIT License
|
||||||
|
* Copyright © 2014-2022 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Actor Model is a design pattern used to handle concurrency in a safe, scalable, and
|
||||||
|
* message-driven way.
|
||||||
|
*
|
||||||
|
* <p>In the Actor Model: - An **Actor** is an independent unit that has its own state and behavior.
|
||||||
|
* - Actors **communicate only through messages** — they do not share memory. - An **ActorSystem**
|
||||||
|
* is responsible for creating, starting, and managing the lifecycle of actors. - Messages are
|
||||||
|
* delivered asynchronously, and each actor processes them one at a time.
|
||||||
|
*
|
||||||
|
* <p>💡 Key benefits: - No shared memory = no need for complex thread-safety - Easy to scale with
|
||||||
|
* many actors - Suitable for highly concurrent or distributed systems
|
||||||
|
*
|
||||||
|
* <p>🔍 This example demonstrates the Actor Model: - `ActorSystem` starts two actors: `srijan` and
|
||||||
|
* `ansh`. - `ExampleActor` and `ExampleActor2` extend the `Actor` class and override the
|
||||||
|
* `onReceive()` method to handle messages. - Actors communicate using `send()` to pass `Message`
|
||||||
|
* objects that include the message content and sender's ID. - The actors process messages
|
||||||
|
* **asynchronously in separate threads**, and we allow a short delay (`Thread.sleep`) to let them
|
||||||
|
* run. - The system is shut down gracefully at the end.
|
||||||
|
*/
|
||||||
|
package com.iluwatar.actormodel;
|
||||||
|
|
||||||
|
public class App {
|
||||||
|
public static void main(String[] args) throws InterruptedException {
|
||||||
|
ActorSystem system = new ActorSystem();
|
||||||
|
Actor srijan = new ExampleActor(system);
|
||||||
|
Actor ansh = new ExampleActor2(system);
|
||||||
|
|
||||||
|
system.startActor(srijan);
|
||||||
|
system.startActor(ansh);
|
||||||
|
ansh.send(new Message("Hello ansh", srijan.getActorId()));
|
||||||
|
srijan.send(new Message("Hello srijan!", ansh.getActorId()));
|
||||||
|
|
||||||
|
Thread.sleep(1000); // Give time for messages to process
|
||||||
|
|
||||||
|
srijan.stop(); // Stop the actor gracefully
|
||||||
|
ansh.stop();
|
||||||
|
system.shutdown(); // Stop the actor system
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
||||||
|
*
|
||||||
|
* The MIT License
|
||||||
|
* Copyright © 2014-2022 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.iluwatar.actormodel;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class ExampleActor extends Actor {
|
||||||
|
private final ActorSystem actorSystem;
|
||||||
|
@Getter private final List<String> receivedMessages = new ArrayList<>();
|
||||||
|
|
||||||
|
public ExampleActor(ActorSystem actorSystem) {
|
||||||
|
this.actorSystem = actorSystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logger log = Logger.getLogger(getClass().getName());
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onReceive(Message message) {
|
||||||
|
LOGGER.info(
|
||||||
|
"[{}]Received : {} from : [{}]", getActorId(), message.getContent(), message.getSenderId());
|
||||||
|
Actor sender = actorSystem.getActorById(message.getSenderId()); // sender actor id
|
||||||
|
// Reply of the message
|
||||||
|
if (sender != null && !message.getSenderId().equals(getActorId())) {
|
||||||
|
sender.send(new Message("I got your message ", getActorId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
||||||
|
*
|
||||||
|
* The MIT License
|
||||||
|
* Copyright © 2014-2022 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.iluwatar.actormodel;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class ExampleActor2 extends Actor {
|
||||||
|
private final ActorSystem actorSystem;
|
||||||
|
@Getter private final List<String> receivedMessages = new ArrayList<>();
|
||||||
|
|
||||||
|
public ExampleActor2(ActorSystem actorSystem) {
|
||||||
|
this.actorSystem = actorSystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onReceive(Message message) {
|
||||||
|
receivedMessages.add(message.getContent());
|
||||||
|
LOGGER.info("[{}]Received : {}", getActorId(), message.getContent());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
||||||
|
*
|
||||||
|
* The MIT License
|
||||||
|
* Copyright © 2014-2022 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.iluwatar.actormodel;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Getter
|
||||||
|
public class Message {
|
||||||
|
private final String content;
|
||||||
|
private final String senderId;
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
||||||
|
*
|
||||||
|
* The MIT License
|
||||||
|
* Copyright © 2014-2022 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.iluwatar.actor;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
import com.iluwatar.actormodel.ActorSystem;
|
||||||
|
import com.iluwatar.actormodel.App;
|
||||||
|
import com.iluwatar.actormodel.ExampleActor;
|
||||||
|
import com.iluwatar.actormodel.ExampleActor2;
|
||||||
|
import com.iluwatar.actormodel.Message;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
public class ActorModelTest {
|
||||||
|
@Test
|
||||||
|
void testMainMethod() throws InterruptedException {
|
||||||
|
App.main(new String[] {});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMessagePassing() throws InterruptedException {
|
||||||
|
ActorSystem system = new ActorSystem();
|
||||||
|
|
||||||
|
ExampleActor srijan = new ExampleActor(system);
|
||||||
|
ExampleActor2 ansh = new ExampleActor2(system);
|
||||||
|
|
||||||
|
system.startActor(srijan);
|
||||||
|
system.startActor(ansh);
|
||||||
|
|
||||||
|
// Ansh recieves a message from Srijan
|
||||||
|
ansh.send(new Message("Hello ansh", srijan.getActorId()));
|
||||||
|
|
||||||
|
// Wait briefly to allow async processing
|
||||||
|
Thread.sleep(200);
|
||||||
|
|
||||||
|
// Check that Srijan received the message
|
||||||
|
assertTrue(
|
||||||
|
ansh.getReceivedMessages().contains("Hello ansh"),
|
||||||
|
"ansh should receive the message from Srijan");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -71,6 +71,7 @@
|
|||||||
<sonar.projectName>Java Design Patterns</sonar.projectName>
|
<sonar.projectName>Java Design Patterns</sonar.projectName>
|
||||||
</properties>
|
</properties>
|
||||||
<modules>
|
<modules>
|
||||||
|
|
||||||
<module>abstract-document</module>
|
<module>abstract-document</module>
|
||||||
<module>abstract-factory</module>
|
<module>abstract-factory</module>
|
||||||
<module>active-object</module>
|
<module>active-object</module>
|
||||||
@@ -243,6 +244,8 @@
|
|||||||
<module>virtual-proxy</module>
|
<module>virtual-proxy</module>
|
||||||
<module>visitor</module>
|
<module>visitor</module>
|
||||||
<module>backpressure</module>
|
<module>backpressure</module>
|
||||||
|
<module>actor-model</module>
|
||||||
|
|
||||||
</modules>
|
</modules>
|
||||||
<repositories>
|
<repositories>
|
||||||
<repository>
|
<repository>
|
||||||
|
|||||||
Reference in New Issue
Block a user