Skip to content

Commit 8ebbb16

Browse files
Passing ExecutorService as parameter instead of lock read
1 parent f92fe0e commit 8ebbb16

1 file changed

Lines changed: 17 additions & 19 deletions

File tree

iterableapi/src/main/java/com/iterable/iterableapi/IterableBackgroundInitializer.java

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,11 @@ void processAll(ExecutorService executor) {
7474
}
7575
isProcessing = false;
7676

77-
// After processing all operations, shut down the executor
77+
// After processing all operations, shut down the executor.
78+
// Pass the executor reference explicitly so a concurrent reset()
79+
// cannot swap in a new one that we accidentally shut down.
7880
IterableLogger.d(TAG, "All queued operations processed, shutting down background executor");
79-
shutdownBackgroundExecutorAsync();
81+
shutdownBackgroundExecutorAsync(backgroundExecutor);
8082
});
8183
}
8284

@@ -334,19 +336,14 @@ static void shutdownBackgroundExecutor() {
334336
}
335337

336338
/**
337-
* Shutdown the background executor asynchronously to avoid blocking the executor thread itself
338-
* Used internally after initialization completes
339+
* Shutdown the given executor asynchronously to avoid blocking the executor thread itself.
340+
* The caller passes the exact executor instance that should be shut down, so a concurrent
341+
* reset() that swaps in a new executor cannot cause us to shut down the wrong one.
339342
*/
340-
private static void shutdownBackgroundExecutorAsync() {
341-
final ExecutorService executorToShutdown;
342-
synchronized (initLock) {
343-
executorToShutdown = backgroundExecutor;
344-
if (executorToShutdown == null || executorToShutdown.isShutdown()) {
345-
return;
346-
}
343+
private static void shutdownBackgroundExecutorAsync(ExecutorService executorToShutdown) {
344+
if (executorToShutdown == null || executorToShutdown.isShutdown()) {
345+
return;
347346
}
348-
// Blocking operations happen outside the lock to avoid deadlock
349-
// (this method is called from a task running on the executor itself)
350347
new Thread(() -> {
351348
try {
352349
executorToShutdown.shutdown();
@@ -417,13 +414,14 @@ static void resetBackgroundInitializationState() {
417414
pendingCallbacks.clear();
418415
callbackManager.reset();
419416

420-
// Always create a fresh executor. The old one may have a pending
421-
// shutdownBackgroundExecutorAsync that hasn't run yet — if we kept it,
422-
// the async shutdown would kill the executor under the next test.
423-
if (backgroundExecutor != null && !backgroundExecutor.isShutdown()) {
424-
backgroundExecutor.shutdownNow();
425-
}
417+
// Swap in a fresh executor first, then shut down the old one.
418+
// This ensures shutdownBackgroundExecutorAsync (which may still be
419+
// pending from the old executor) cannot kill the new one.
420+
ExecutorService oldExecutor = backgroundExecutor;
426421
backgroundExecutor = createExecutor();
422+
if (oldExecutor != null && !oldExecutor.isShutdown()) {
423+
oldExecutor.shutdownNow();
424+
}
427425
}
428426
}
429427

0 commit comments

Comments
 (0)