openj9
openj9 copied to clipboard
Thread::getState is a scalability issue
Java -version output
All versions
Summary of problem
The Netty project was using Thread::getState on a non-current thread. Due to needing to halt the thread for inspection, there was a scalability issue when using Netty on OpenJ9.
They've worked around it by calling Thread::isAlive instead for OpenJ9, but this kind of lingering scalability issue may affect others as well.
Original issue: https://github.com/netty/netty/issues/13347#issuecomment-1518537895 Workaround: https://github.com/netty/netty/pull/13357
fyi @babsingh @gacholio
Potential solution: Add a field in j.l.Thread which will store the current state of the Java thread. It will be atomically updated as the Java thread goes through the various state transitions in native and Java code. With this approach, Thread::getState will require to atomically read the new field without the need to halt the thread for inspection.
We've talked about this for years - there's no need for an atomic update. Like so many APIs, the return value is momentary, likely to be different a few instructions later.
In some stress tests I ran, the expense comes mostly from calling into native code and computing the state lazily; not so much from needing to halt the thread.
Adding a field (or using an existing unused field) to j.l.Thread then setting it on state transitions in our native code, like Babneet suggested, will alleviate this cost from the getState calls.
For the Java 19+ code, j.l.Thread has a nested FieldHolder class that holds a threadStatus field; we can use this to hold the thread state. We currently don't use this field for anything.
In pre-Java 19 j.l.Thread code, we can add this field in the same way as the other fields held in FieldHolder.
git blame shows that upstream uses this field similarly to what we've proposed here.
Updating thread state on transition instead of trying to derive it based on other information seems sensible to me.