question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

`PropertyNamingStrategy` class initialization depends on its subclass, this can lead to class loading deadlock

See original GitHub issue

If a class refer to its subclasses in its static initializers or in static fields, this references can cause JVM-level deadlocks in multithreaded environment, when one thread tries to load superclass and another thread tries to load subclass at the same time.

See: https://bugs.openjdk.java.net/browse/JDK-8037567

The following demo code can reproduce this deadlock

public class ClassInitDeadLock {

    public static void main(String[] args) throws InterruptedException {
        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                // trigger supper class initialize
                PascalCaseStrategy strategy = PropertyNamingStrategy.PASCAL_CASE_TO_CAMEL_CASE;
            }
        }, "Thread-A");

        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                // trigger sub class initialize
                PascalCaseStrategy strategy = new PascalCaseStrategy();
            }
        }, "Thread-B");

        threadA.start();
        Thread.sleep(100);
        threadB.start();
    }

    public static class PropertyNamingStrategy {
        static {
            try {
                // sleep 1s for deadlock reproduction
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // ignore
            }
        }

        public static final PascalCaseStrategy PASCAL_CASE_TO_CAMEL_CASE = new PascalCaseStrategy();
    }

    public static class PascalCaseStrategy extends PropertyNamingStrategy {
    }
}

When the demo program ClassInitDeadLock started, it could not exit automatically. Thread-A holding PropertyNamingStrategy class , and waiting PascalCaseStrategy class initialize, while Thread-B holding PascalCaseStrategy class, and waiting PropertyNamingStrategy class initialize, deadlock occurred!

jstack of these two thread:

"Thread-A" #11 prio=5 os_prio=31 tid=0x00007fa8c29d8000 nid=0xa803 in Object.wait() [0x000070000a4c4000]
   java.lang.Thread.State: RUNNABLE
	at ClassInitDeadLock$PropertyNamingStrategy.<clinit>(ClassInitDeadLock.java:35)
	at ClassInitDeadLock$1.run(ClassInitDeadLock.java:8)
	at java.lang.Thread.run(Thread.java:748)

"Thread-B" #12 prio=5 os_prio=31 tid=0x00007fa8c4a9b800 nid=0x5603 in Object.wait() [0x000070000a5c7000]
   java.lang.Thread.State: RUNNABLE
	at ClassInitDeadLock$2.run(ClassInitDeadLock.java:16)
	at java.lang.Thread.run(Thread.java:748)

In the actual environment, PropertyNamingStrategy and its subclass defined in jackson-databind initialize very fast, so It’s hard to produce the scene that multithread load superclass and subclass at the same time.

I happened to meet this deadlock recently, It turn out to be JsonErrorUnmarshaller.java#L37 defined in aws-java-sdk-core, trying to initialize subclass PascalCaseStrategy, at the same time, another thread is initilizing superclass PropertyNamingStrategy

private static final ObjectMapper MAPPER = new ObjectMapper().configure(
        DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).setPropertyNamingStrategy(
        new PascalCaseStrategy());

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:6 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
cowtowncodercommented, May 23, 2020

Unfortunately I think the solution can only go in 2.12, as I need to add PropertyNamingStrategies as the place for static instances, deprecate existing entries; that is, making API changes that need to go in a new minor version.

1reaction
cowtowncodercommented, Aug 13, 2020

@fangwentong Yes. I think for databind itself, will probably need to introduce something like PropertyNamingStrategies to hold instances (which would have been good to do from beginning as a pattern). And then deprecate sub-type static instance.

Read more comments on GitHub >

github_iconTop Results From Across the Web

What does "class loading deadlock" mean here?
The deadlock can only occur if you have 2 threads and one starts to load User and one starts to load NonRegisteredUser ....
Read more >
Security update for jackson-databind, jackson-dataformats ...
Record') + 'PropertyNamingStrategy' class initialization depends on its subclass, this can lead to class loading deadlock + ...
Read more >
When a class is loaded and initialized in JVM - Java Example
In this Java tutorial, we will see when class loading occurs in Java and when and how class ... Reflection can also cause...
Read more >
S-Index (Spring Framework 4.3.0.RC2 API)
Set whether the factory is allowed to eagerly load bean classes even for bean definitions that are marked as "lazy-init".
Read more >
Deadlocks in Java class initialisation - farblog
I recently ran across the fact that it's possible to make the Java runtime deadlock while initialising a class — and that this...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found