This is an automated email from the ASF dual-hosted git repository.
rzo1 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomee.git
The following commit(s) were added to refs/heads/main by this push:
new b7c2145835 Fix deadlock in static initialization of Core introduced
with #2521 Do not refactor to lambda expressions as it will result in a
class-initialization deadlock
b7c2145835 is described below
commit b7c2145835e73a72d258b1b9eca36ab3e1638d00
Author: Richard Zowalla <[email protected]>
AuthorDate: Thu Mar 5 08:32:50 2026 +0100
Fix deadlock in static initialization of Core introduced with #2521
Do not refactor to lambda expressions as it will result in a
class-initialization deadlock
---
.../src/main/java/org/apache/openejb/Core.java | 52 +++++++++++++++++-----
1 file changed, 41 insertions(+), 11 deletions(-)
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/Core.java
b/container/openejb-core/src/main/java/org/apache/openejb/Core.java
index 495f7297b6..6d4c39abfb 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/Core.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/Core.java
@@ -26,21 +26,51 @@ import java.util.concurrent.Semaphore;
* @version $Rev$ $Date$
*/
public class Core {
+
+ /*
+ * IMPORTANT: Do NOT refactor the anonymous threads in this class to
lambda expressions.
+ *
+ * Reason:
+ * This code runs during static class initialization. The main thread
holds the
+ * class-initialization lock for Core while starting worker threads and
waiting
+ * for them.
+ *
+ * If lambdas are used, the lambda body is compiled into a synthetic method
+ * inside the Core class. When the spawned thread tries to execute the
lambda,
+ * it must access that synthetic method, which requires Core to be fully
+ * initialized. However, the main thread is still holding the
initialization
+ * lock and waiting for the worker thread to finish.
+ *
+ * This results in a class-initialization deadlock:
+ * - Main thread waits for worker thread
+ * - Worker thread waits for Core initialization to complete
+ *
+ * Anonymous inner classes avoid this problem because they are compiled as
+ * separate classes (e.g. Core$1.class) and can execute without requiring
+ * Core to finish initialization.
+ *
+ */
static {
- final Thread preloadMessages = new Thread(() -> {
- new Messages("org.apache.openejb.util.resources");
- new Messages("org.apache.openejb.config");
- new Messages("org.apache.openejb.config.resources");
- });
+ final Thread preloadMessages = new Thread() {
+ @Override
+ public void run() {
+ new Messages("org.apache.openejb.util.resources");
+ new Messages("org.apache.openejb.config");
+ new Messages("org.apache.openejb.config.resources");
+ }
+ };
preloadMessages.start();
- final Thread preloadServiceProviders = new Thread(() -> {
- try {
- ServiceUtils.getServiceProviders();
- } catch (final OpenEJBException e) {
- // no-op
+ final Thread preloadServiceProviders = new Thread() {
+ @Override
+ public void run() {
+ try {
+ ServiceUtils.getServiceProviders();
+ } catch (final OpenEJBException e) {
+ // no-op
+ }
}
- });
+ };
preloadServiceProviders.start();
final int permits = 2 * Runtime.getRuntime().availableProcessors() + 1;