Skip to content

Commit 71c15cb

Browse files
committed
Avoid possible livelock when stopping FileSystemWatcher in parallel
Previously, if the file watcher thread tried to stop the FileSystemWatcher when another thread was already stopping it a livelock could occur. The livelock occurred because the file watcher thread would attempt to lock a monitor that was being held by a thread that had joined the file watcher thread and was waiting for it to die. This commit avoid the livelock by narrowing the synchronization that's used when stopping the FileSystemWatcher. The monitor is used to obtain a reference to the file watcher thread in a thread-safe manner, but it is released prior to joining the file watcher thread and waiting for it to die. This will allow a parallel attempt by the file watcher thread to stop itself to succeed. Closes gh-10496
1 parent 205c25b commit 71c15cb

File tree

1 file changed

+12
-11
lines changed

1 file changed

+12
-11
lines changed

spring-boot-devtools/src/main/java/org/springframework/boot/devtools/filewatch/FileSystemWatcher.java

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2016 the original author or authors.
2+
* Copyright 2012-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -183,22 +183,23 @@ public void stop() {
183183
* @param remainingScans the number of remaining scans
184184
*/
185185
void stopAfter(int remainingScans) {
186+
Thread thread = null;
186187
synchronized (this.monitor) {
187-
Thread thread = this.watchThread;
188+
thread = this.watchThread;
188189
if (thread != null) {
189190
this.remainingScans.set(remainingScans);
190191
if (remainingScans <= 0) {
191192
thread.interrupt();
192193
}
193-
if (Thread.currentThread() != thread) {
194-
try {
195-
thread.join();
196-
}
197-
catch (InterruptedException ex) {
198-
Thread.currentThread().interrupt();
199-
}
200-
}
201-
this.watchThread = null;
194+
}
195+
this.watchThread = null;
196+
}
197+
if (Thread.currentThread() != thread) {
198+
try {
199+
thread.join();
200+
}
201+
catch (InterruptedException ex) {
202+
Thread.currentThread().interrupt();
202203
}
203204
}
204205
}

0 commit comments

Comments
 (0)