-
-
Notifications
You must be signed in to change notification settings - Fork 27.4k
server-session: remove busy-wait loop in App.java using ScheduledExecutorService #3445
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
5b89975
3156d06
0c0ebab
cfb221d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,6 +31,7 @@ | |
| import java.util.HashMap; | ||
| import java.util.Iterator; | ||
| import java.util.Map; | ||
| import java.util.concurrent.*; | ||
| import lombok.extern.slf4j.Slf4j; | ||
|
|
||
| /** | ||
|
|
@@ -57,6 +58,9 @@ public class App { | |
| private static Map<String, Instant> sessionCreationTimes = new HashMap<>(); | ||
| private static final long SESSION_EXPIRATION_TIME = 10000; | ||
|
|
||
| private static final ScheduledExecutorService scheduler = | ||
| Executors.newSingleThreadScheduledExecutor(Thread.ofVirtual().factory()); | ||
|
|
||
| /** | ||
| * Main entry point. | ||
| * | ||
|
|
@@ -78,39 +82,39 @@ public static void main(String[] args) throws IOException { | |
| sessionExpirationTask(); | ||
|
|
||
| LOGGER.info("Server started. Listening on port 8080..."); | ||
|
|
||
| Runtime.getRuntime().addShutdownHook(new Thread(() -> { | ||
| LOGGER.info("Shutting down scheduler..."); | ||
| scheduler.shutdown(); | ||
| })); | ||
| } | ||
|
|
||
| private static void sessionExpirationTask() { | ||
| new Thread( | ||
| () -> { | ||
| 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) { | ||
| Iterator<Map.Entry<String, Instant>> iterator = | ||
| sessionCreationTimes.entrySet().iterator(); | ||
| while (iterator.hasNext()) { | ||
| Map.Entry<String, Instant> entry = iterator.next(); | ||
| if (entry | ||
| .getValue() | ||
| .plusMillis(SESSION_EXPIRATION_TIME) | ||
| .isBefore(currentTime)) { | ||
| sessions.remove(entry.getKey()); | ||
| iterator.remove(); | ||
| } | ||
| } | ||
| } | ||
| scheduler | ||
| .scheduleAtFixedRate(() -> { | ||
| try { | ||
| LOGGER.info("Session expiration checker started..."); | ||
| Instant currentTime = Instant.now(); | ||
| synchronized (sessions) { | ||
| synchronized (sessionCreationTimes) { | ||
| Iterator<Map.Entry<String, Instant>> iterator = | ||
| sessionCreationTimes.entrySet().iterator(); | ||
| while (iterator.hasNext()) { | ||
| Map.Entry<String, Instant> 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(); | ||
| } | ||
| } | ||
| }) | ||
| .start(); | ||
| } | ||
| LOGGER.info("Session expiration checker finished!"); | ||
| } catch (Exception e) { | ||
| LOGGER.error("An error occurred: ", e); | ||
| } | ||
| }, SESSION_EXPIRATION_TIME, SESSION_EXPIRATION_TIME, TimeUnit.MILLISECONDS); | ||
| } | ||
| } | ||
| } | ||
|
Comment on lines
+97
to
+123
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The session expiration task is now scheduled with a fixed-rate executor. It eliminates the busy-wait loop in main and uses a synchronized block around the two maps. Potential deadlock risk exists due to nested synchronization on separate locks; consider consolidating to a single lock or using a concurrent map approach to avoid nested locks. |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replaced busy-wait loop with a scheduled task that periodically checks for expired sessions. The code uses a fixed-rate schedule with a 10s interval and safely removes expired sessions under synchronized access to shared maps.