From 47ac0693df267644c3950ec26a23327748f2c5c7 Mon Sep 17 00:00:00 2001 From: Senrian <47714364+Senrian@users.noreply.github.com> Date: Fri, 20 Mar 2026 18:37:39 +0800 Subject: [PATCH 1/3] docs: clarify Immutable Object pattern in Value Object README (fixes #3448) --- value-object/README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/value-object/README.md b/value-object/README.md index 84b8e029debd..e1e8dc3b14d0 100644 --- a/value-object/README.md +++ b/value-object/README.md @@ -18,14 +18,16 @@ tag: ## Also known as -* Embedded Value * Immutable Object +* Embedded Value * Inline Value * Integrated Value -## Intent of Value Object Design Pattern +## Intent of Value Object / Immutable Object Design Pattern -The Value Object pattern in Java creates immutable objects that represent a descriptive aspect of the domain with no conceptual identity. It aims to enhance performance and reduce memory overhead by storing frequently accessed immutable data directly within the object that uses it, rather than separately. +The Value Object pattern (also known as the **Immutable Object pattern**) in Java creates immutable objects that represent a descriptive aspect of the domain with no conceptual identity. It aims to enhance performance and reduce memory overhead by storing frequently accessed immutable data directly within the object that uses it, rather than separately. + +The Immutable Object pattern ensures that an object's state cannot be modified after construction, providing thread-safety and predictability in concurrent scenarios. ## Detailed Explanation of Value Object Pattern with Real-World Examples @@ -146,3 +148,4 @@ Trade-offs: * [J2EE Design Patterns](https://amzn.to/4dpzgmx) * [Patterns of Enterprise Application Architecture](https://amzn.to/3WfKBPR) * [ValueObject (Martin Fowler)](https://martinfowler.com/bliki/ValueObject.html) + From efa3e183fa6d6391ebf31fc7cc705591264044d8 Mon Sep 17 00:00:00 2001 From: Senrian <47714364+Senrian@users.noreply.github.com> Date: Thu, 26 Mar 2026 16:14:24 +0800 Subject: [PATCH 2/3] fix: replace busy-waiting with ScheduledExecutorService using virtual threads Replace the busy-waiting Thread with true sleep + virtual threads in SessionExpirationChecker. --- .../main/java/com/iluwatar/sessionserver/App.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/server-session/src/main/java/com/iluwatar/sessionserver/App.java b/server-session/src/main/java/com/iluwatar/sessionserver/App.java index 512447b8a2d9..549a9a4f652b 100644 --- a/server-session/src/main/java/com/iluwatar/sessionserver/App.java +++ b/server-session/src/main/java/com/iluwatar/sessionserver/App.java @@ -31,6 +31,9 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import lombok.extern.slf4j.Slf4j; /** @@ -57,6 +60,10 @@ public class App { private static Map sessionCreationTimes = new HashMap<>(); private static final long SESSION_EXPIRATION_TIME = 10000; + private static final ScheduledExecutorService sessionScheduler = + Executors.newSingleThreadScheduledExecutor( + Thread.ofVirtual().name("session-scheduler-", 1).factory()); + /** * Main entry point. * @@ -86,7 +93,6 @@ private static void sessionExpirationTask() { while (true) { try { LOGGER.info("Session expiration checker started..."); - Thread.sleep(SESSION_EXPIRATION_TIME); // Sleep for expiration time Instant currentTime = Instant.now(); synchronized (sessions) { synchronized (sessionCreationTimes) { @@ -110,7 +116,9 @@ private static void sessionExpirationTask() { Thread.currentThread().interrupt(); } } - }) - .start(); + }, + 0, + SESSION_EXPIRATION_TIME, + TimeUnit.MILLISECONDS); } } From 644640708d0de9baa05bf8dd9f1c8f15ec08d855 Mon Sep 17 00:00:00 2001 From: Senrian <47714364+Senrian@users.noreply.github.com> Date: Thu, 26 Mar 2026 16:47:56 +0800 Subject: [PATCH 3/3] fix: correct ScheduledExecutorService usage - no inner infinite loop Use scheduleAtFixedRate correctly without inner while(true) loop. Virtual threads eliminate busy-waiting concerns. --- .../java/com/iluwatar/sessionserver/App.java | 55 +++++++++---------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/server-session/src/main/java/com/iluwatar/sessionserver/App.java b/server-session/src/main/java/com/iluwatar/sessionserver/App.java index 549a9a4f652b..d8ce5787b6bd 100644 --- a/server-session/src/main/java/com/iluwatar/sessionserver/App.java +++ b/server-session/src/main/java/com/iluwatar/sessionserver/App.java @@ -88,37 +88,34 @@ public static void main(String[] args) throws IOException { } private static void sessionExpirationTask() { - new Thread( - () -> { - while (true) { - try { - LOGGER.info("Session expiration checker started..."); - Instant currentTime = Instant.now(); - synchronized (sessions) { - synchronized (sessionCreationTimes) { - Iterator> iterator = - sessionCreationTimes.entrySet().iterator(); - while (iterator.hasNext()) { - Map.Entry entry = iterator.next(); - if (entry - .getValue() - .plusMillis(SESSION_EXPIRATION_TIME) - .isBefore(currentTime)) { - sessions.remove(entry.getKey()); - iterator.remove(); - } - } - } + sessionScheduler.scheduleAtFixedRate( + () -> { + try { + LOGGER.info("Session expiration checker started..."); + Instant currentTime = Instant.now(); + synchronized (sessions) { + synchronized (sessionCreationTimes) { + Iterator> iterator = + sessionCreationTimes.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + if (entry + .getValue() + .plusMillis(SESSION_EXPIRATION_TIME) + .isBefore(currentTime)) { + sessions.remove(entry.getKey()); + iterator.remove(); } - LOGGER.info("Session expiration checker finished!"); - } catch (InterruptedException e) { - LOGGER.error("An error occurred: ", e); - Thread.currentThread().interrupt(); } } - }, - 0, - SESSION_EXPIRATION_TIME, - TimeUnit.MILLISECONDS); + } + LOGGER.info("Session expiration checker finished!"); + } catch (Exception e) { + LOGGER.error("An error occurred: ", e); + } + }, + 0, + SESSION_EXPIRATION_TIME, + TimeUnit.MILLISECONDS); } }