Skip to content

Commit f62b910

Browse files
BoxStore: actually print thread stacks if pool isn't shut down in time #258
Previously Thread.dumpStack() was used which only prints the stack of the current thread. Also *all* existing threads were printed, not just those from the internal thread pool.
1 parent 53615b5 commit f62b910

File tree

3 files changed

+25
-8
lines changed

3 files changed

+25
-8
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ For more insights into what changed in the ObjectBox C++ core, [check the Object
1010
an "Another BoxStore is still open for this directory" exception. Note that calling `close()` *is recommended* before
1111
creating a new instance. [#1201](https://github.com/objectbox/objectbox-java/issues/1201)
1212
- When using `BoxStoreBuilder.buildDefault()`, don't leak Store when setting as default fails.
13+
- To help diagnose, print stacks of all threads in the internal thread pool if shutting it down takes too long when
14+
closing `BoxStore`.
1315

1416
## 4.3.1 - 2025-08-12
1517

objectbox-java/src/main/java/io/objectbox/BoxStore.java

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -743,18 +743,31 @@ public void close() {
743743
}
744744
}
745745

746-
/** dump thread stacks if pool does not terminate promptly. */
746+
/**
747+
* Waits briefly for the internal {@link #threadPool} to terminate. If it does not terminate in time, prints stack
748+
* traces of the pool threads.
749+
*/
747750
private void checkThreadTermination() {
748751
try {
749752
if (!threadPool.awaitTermination(1, TimeUnit.SECONDS)) {
750-
int activeCount = Thread.activeCount();
751-
getErrorOutput().println("Thread pool not terminated in time; printing stack traces...");
752-
Thread[] threads = new Thread[activeCount + 2];
753+
getErrorOutput().println("ObjectBox thread pool not terminated in time." +
754+
" Ensure all async calls have completed and subscriptions are cancelled before closing the Store." +
755+
"\nPrinting pool threads...");
756+
// Note: this may not print any pool threads if other threads are started while enumerating
757+
// (and the pool threads do not make it into the threads array).
758+
Thread[] threads = new Thread[Thread.activeCount()];
753759
int count = Thread.enumerate(threads);
754760
for (int i = 0; i < count; i++) {
755-
getErrorOutput().println("Thread: " + threads[i].getName());
756-
Thread.dumpStack();
761+
Thread thread = threads[i];
762+
if (thread.getName().startsWith(ObjectBoxThreadPool.THREAD_NAME_PREFIX)) {
763+
getErrorOutput().println("Thread: " + thread.getName());
764+
StackTraceElement[] trace = thread.getStackTrace();
765+
for (StackTraceElement traceElement : trace) {
766+
getErrorOutput().println("\tat " + traceElement);
767+
}
768+
}
757769
}
770+
getErrorOutput().println("Printing pool threads...DONE");
758771
}
759772
} catch (InterruptedException e) {
760773
e.printStackTrace(getErrorOutput());

objectbox-java/src/main/java/io/objectbox/internal/ObjectBoxThreadPool.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017 ObjectBox Ltd.
2+
* Copyright 2017-2024 ObjectBox Ltd.
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.
@@ -36,6 +36,8 @@
3636
*/
3737
@Internal
3838
public class ObjectBoxThreadPool extends ThreadPoolExecutor {
39+
40+
public static String THREAD_NAME_PREFIX = "ObjectBox-";
3941
private final BoxStore boxStore;
4042

4143
public ObjectBoxThreadPool(BoxStore boxStore) {
@@ -54,7 +56,7 @@ static class ObjectBoxThreadFactory implements ThreadFactory {
5456
private static final AtomicInteger POOL_COUNT = new AtomicInteger();
5557

5658
private final ThreadGroup group;
57-
private final String namePrefix = "ObjectBox-" + POOL_COUNT.incrementAndGet() + "-Thread-";
59+
private final String namePrefix = THREAD_NAME_PREFIX + POOL_COUNT.incrementAndGet() + "-Thread-";
5860
private final AtomicInteger threadCount = new AtomicInteger();
5961

6062
ObjectBoxThreadFactory() {

0 commit comments

Comments
 (0)