• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Hyshmily / hotkey / 28637103998

03 Jul 2026 03:48AM UTC coverage: 90.399% (-0.2%) from 90.63%
28637103998

push

github

Hyshmily
fix: add packaging to gitignore, fix flaky jitter test, update docs references

Signed-off-by: Hyshmily <cxm8607@outlook.com>

1264 of 1461 branches covered (86.52%)

Branch coverage included in aggregate %.

3604 of 3924 relevant lines covered (91.85%)

4.19 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

67.74
/common/src/main/java/io/github/hyshmily/hotkey/util/TimeSource.java
1
/*
2
 * Copyright 2026 Hyshmily. All Rights Reserved.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package io.github.hyshmily.hotkey.util;
17

18
import io.github.hyshmily.hotkey.Internal;
19
import java.util.concurrent.atomic.AtomicBoolean;
20
import java.util.concurrent.atomic.AtomicInteger;
21
import lombok.extern.slf4j.Slf4j;
22

23
/**
24
 * Performance-optimized clock source that caches {@link System#currentTimeMillis()}
25
 * on a low-frequency background thread (every 5ms) to avoid the cost of a
26
 * {@code native} call on every read via {@link #currentTimeMillis()}.
27
 * <p>
28
 * The background daemon thread is started once via {@link #start()} and runs
29
 * for the lifetime of the JVM.  If the thread is interrupted it silently falls
30
 * back to calling {@link System#currentTimeMillis()} directly.
31
 * <p>
32
 * All time-sensitive components in the hot-path (expiry, rate limiting, circuit
33
 * breaker) use this source instead of {@code System.currentTimeMillis()}.
34
 */
35
@Internal
36
@Slf4j
3✔
37
public final class TimeSource {
38

39
  private static volatile long currentMillis = System.currentTimeMillis();
2✔
40
  private static final AtomicBoolean threadRunning = new AtomicBoolean(false);
5✔
41
  private static final AtomicInteger threadTryCount = new AtomicInteger(0);
6✔
42
  private static final int THREAD_TRY_MAX = 3;
43

44
  /**
45
   * Start the background clock-cache thread.  Idempotent after the thread is
46
   * running.  If the thread dies unexpectedly it will be restarted up to
47
   * {@link #THREAD_TRY_MAX} times with a 1-second delay between attempts.
48
   * Called automatically during {@code HotKeyFacadeAutoConfiguration}
49
   * initialisation.
50
   */
51
  @SuppressWarnings("BusyWait")
52
  public static void start() {
53
    if (threadTryCount.incrementAndGet() <= THREAD_TRY_MAX && threadRunning.compareAndSet(false, true)) {
9✔
54
      Thread t = new HotKeyThreadFactory("TimeSource").newThread(() -> {
7✔
55
        while (threadRunning.get()) {
3!
56
          currentMillis = System.currentTimeMillis();
2✔
57
          try {
58
            Thread.sleep(5);
2✔
59
          } catch (InterruptedException ignored) {
×
60
            threadRunning.set(false);
×
61
          }
1✔
62
        }
63
      });
×
64
      t.setUncaughtExceptionHandler((th, ex) -> {
3✔
65
        log.error("TimeSource thread terminated unexpectedly, will restart after 1s.", ex);
×
66
        threadRunning.set(false);
×
67
        try {
68
          Thread.sleep(1000);
×
69
        } catch (InterruptedException ignored) {}
×
70
        start();
×
71
      });
×
72
      t.start();
2✔
73
    }
74
  }
1✔
75

76
  /**
77
   * Returns the current time in milliseconds since the epoch.
78
   * <p>
79
   * When the background thread is running, this returns the cached value
80
   * updated every 5ms — avoiding a {@code native} JNI call on every read.
81
   * Falls back to {@link System#currentTimeMillis()} if the thread has not
82
   * been started or was interrupted.
83
   *
84
   * @return current time in milliseconds (epoch-based)
85
   */
86
  public static long currentTimeMillis() {
87
    return threadRunning.get() ? currentMillis : System.currentTimeMillis();
7✔
88
  }
89

90
  private TimeSource() {}
91
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc