On Thu, 9 Jul 2026 17:55:55 GMT, Andy Goryachev <[email protected]> wrote:
>> John Hendrikx has updated the pull request incrementally with one additional
>> commit since the last revision:
>>
>> Fix flakey check on (asynchronous) stderr output
>
> modules/javafx.base/src/main/java/com/sun/javafx/binding/ListenerListBase.java
> line 423:
>
>> 421:
>> 422: private int totalSize() {
>> 423: return isLocked() ? lockedSize : invalidationListenersCount +
>> changeListenersCount;
>
> what happens when an invalidation listener removes all the change listeners
> while it's locked? the totalSize() will report incorrect value, breaking
> downstream logic, right?
`totalSize` is not called by anything other than `hasChangeListeners`, which
simply uses it to see if it is greater than `invalidationListenerCount`. If
yes, then there must be change listeners.
The scenario you described works as follows:
- A notification starts
- List is locked (which locks `totalSize` to the current size for the duration
of the lock)
- An invalidation listener is triggered that removes all change listeners
- As the list is locked, this results in those change listeners being replaced
with `null` values rather than removed, preserving the listener indices
- Notification proceeds and starts iterating through the change listeners
- Every one of those is `null` and is skipped
- List is unlocked (list gets consolidated, nulls are removed)
- Notification ends
Before removal:
listener slots (with say C, D and E being change listeners, and A or B being
the invalidation listener that removes the change listeners):
+---+---+---+---+---+
| A | B | C | D | E |
+---+---+---+---+---+
^ ^
invalidation totalSize() == 5
While locked, an invalidation listener removes C, D, and E:
listener slots
+---+---+----+----+----+
| A | B |null|null|null|
+---+---+----+----+----+
^ ^
invalidation totalSize() is still 5
-------------
PR Review Comment: https://git.openjdk.org/jfx/pull/1081#discussion_r3561967665