Why Java’s WatchService Misses File Changes and How to Fix It
This article examines a JDK bug that drops millisecond precision in file timestamps, explains why Java’s WatchService falls back to polling on macOS, contrasts it with Linux’s inotify‑based implementation, and shares practical workarounds for reliable file change detection.
From a Real‑World Failure
Our configuration service writes files via an agent, and a client program watches those files for changes. The initial implementation used a dedicated thread that periodically polls each file’s last‑modified timestamp (millisecond precision) to detect updates.
Two drawbacks existed: the poll interval caused delayed detection, and if two changes occurred within the same millisecond the second could be missed. In practice these issues were minor—until a JDK bug surfaced.
The JDK Bug
In certain JDK versions (see bug 8177809 ) the File.lastModified() method loses millisecond precision and returns whole‑second timestamps. A demo on macOS showed that with JDK 1.8.0_261 the timestamps retained milliseconds, while JDK 11.0.6 truncated them.
WatchService – Java’s Built‑in File Watcher
Java provides WatchService to monitor a directory for create, modify, delete, and overflow events. A simple demo registers /tmp/file_test and writes to a file every 5 ms. Expected three modify events were observed only after about 9.5 seconds, indicating a polling delay.
public static void watchDir(String dir) {
Path path = Paths.get(dir);
try (WatchService watchService = FileSystems.getDefault().newWatchService()) {
path.register(watchService,
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_MODIFY,
StandardWatchEventKinds.ENTRY_DELETE,
StandardWatchEventKinds.OVERFLOW);
while (true) {
WatchKey key = watchService.take();
for (WatchEvent<?> watchEvent : key.pollEvents()) {
if (watchEvent.kind() == StandardWatchEventKinds.ENTRY_CREATE) {
System.out.println("create..." + System.currentTimeMillis());
} else if (watchEvent.kind() == StandardWatchEventKinds.ENTRY_MODIFY) {
System.out.println("modify..." + System.currentTimeMillis());
} else if (watchEvent.kind() == StandardWatchEventKinds.ENTRY_DELETE) {
System.out.println("delete..." + System.currentTimeMillis());
} else if (watchEvent.kind() == StandardWatchEventKinds.OVERFLOW) {
System.out.println("overflow..." + System.currentTimeMillis());
}
}
if (!key.reset()) {
System.out.println("reset false");
return;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}WatchService Internals
Debugging revealed that on macOS the returned instance is sun.nio.fs.PollingWatchService, which internally starts a thread that polls every 10 seconds. The polling logic mirrors our original implementation—reading the file’s last‑modified time and generating events based on changes—so it inherits the same JDK bug.
Inotify – Linux’s Native File Watcher
Linux provides the inotify system call for real‑time file change notifications. Java’s LinuxWatchService leverages this, offering immediate events without the 10‑second delay. A native library (e.g., Jinotify ) can expose inotify directly to Java, but it requires compiling a .so file.
Why macOS Falls Back to Polling
The JDK documentation notes that when the underlying platform does not support inotify, it falls back to a polling implementation. Consequently, on macOS the WatchService uses PollingWatchService, while on Linux it uses LinuxWatchService.
Verification with strace
Running strace -f -o s.txt java FileTime on Linux shows inotify system calls, confirming the native implementation.
How We Fixed the Issue
To avoid the timestamp bug, we added a separate version file containing the MD5 hash of the configuration file. The client reads the version file first; when the hash changes, it reloads the actual configuration.
We considered using WatchService directly, but in Docker environments inotify can lose events, a problem not limited to Java.
Takeaway
Even well‑tested APIs can hide platform‑specific bugs. Understanding the underlying implementation—polling versus inotify—helps choose the right strategy for reliable file change detection.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Su San Talks Tech
Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
