This guide explains how Chronicle Threads enforces single-threaded handler execution and how developers should structure code that interacts with event loops.
It expands on requirements THR-FN-006 through THR-NF-O-009 and aligns with Chronicle Core’s SingleThreadedChecked utilities.
Read this guide together with:
-
architecture-overview.adoc – for loop topology and handler placement.
-
thread-performance-targets.adoc – for performance expectations that influence safe handler design.
-
operational-controls.adoc – for operational safeguards that rely on thread-safety guarantees.
-
Each
EventLoopruns on a dedicated Java platform thread; handlers registered on that loop must not share mutable state with other threads without explicit synchronisation (THR-FN-006). -
When a handler needs to hand over work to another thread (e.g., a blocking worker), use thread-safe queues or Chronicle Queue to transfer data without violating loop confinement.
-
The boolean result of
action()should reflect whether more immediate work is available; returningtruerepeatedly for idle handlers forces tight scheduling and increases contention for other handlers (THR-FN-007).
- Initialise
-
Construct handlers and supporting resources on the main thread, then call
singleThreadedCheckReset()before registering them with the target loop. - Operate
-
Once registered, treat handler state as confined to the loop’s thread. All mutations should occur inside
action()or helper methods invoked from that loop. - Dispose
-
Use
InvalidEventHandlerException.reusable()to self-deregister when the handler has completed its lifecycle (THR-FN-008). Ensure downstream resources honour Chronicle Core’sCloseableandReferenceCountedcontracts.
-
Shared caches or maps must expose lock-free APIs that are safe for single-writer, multi-reader scenarios, or provide appropriate synchronisation.
-
When invoking Chronicle Queue appenders or tailers from handlers, rely on their single-threaded guarantees and avoid sharing instances across loops without resetting ownership.
-
If a handler must update shared analytics or metrics collectors, prefer non-blocking data structures (e.g.,
LongAdder) to minimise stall risk.
- Unchecked exceptions
-
-
The loop removes the offending handler and logs via
Jvm.warn(); implement catch-and-report patterns where recovery is possible (THR-NF-O-009).
-
- Timeouts
-
-
Use monitor-loop thresholds to detect blocked handlers early (THR-NF-O-018). Handlers can emit domain-specific heartbeats to aid diagnosis.
-
- Defensive coding
-
-
Validate external inputs before entering tight loops to avoid unbounded CPU usage.
-
Leverage Chronicle Core’s
SingleThreadedCheckedexceptions during testing to catch accidental cross-thread access.
-
-
Run unit tests with assertions enabled to surface
SingleThreadedCheckedviolations. -
Use deterministic executors in integration tests to simulate loop progression and ensure handlers remain idempotent.
-
Incorporate concurrency stress tests that replay boundary scenarios (e.g., handler self-deregistration while monitor loop samples metrics).
-
Annotate handler classes with the relevant requirement IDs (e.g.,
THR-FN-006) in code comments or design docs to aid reviews. -
Update operational run-books to describe ownership expectations and hand-off procedures.
-
Ensure new handlers ship with accompanying tests that prove thread-safety assumptions, referencing requirement IDs in test names where practical.