Revert use of Map::computeIfAbsent in thread and tx scopes

Issues gh-25038 and gh-25618 collectively introduced a regression for
thread-scoped and transaction-scoped beans.

For example, given a thread-scoped bean X that depends on another
thread-scoped bean Y, if the names of the beans (when used as map keys)
end up in the same bucket within a ConcurrentHashMap AND an attempt is
made to retrieve bean X from the ApplicationContext prior to retrieving
bean Y, then the use of Map::computeIfAbsent in SimpleThreadScope
results in recursive access to the same internal bucket in the map.

On Java 8, that scenario simply hangs. On Java 9 and higher,
ConcurrentHashMap throws an IllegalStateException pointing out that a
"Recursive update" was attempted.

In light of these findings, we are reverting the changes made to
SimpleThreadScope and SimpleTransactionScope in commits 50a4fdac6e and
148dc95eb1.

Closes gh-25801
This commit is contained in:
Sam Brannen
2020-09-25 10:55:32 +02:00
parent a532c527dd
commit f5d36aa47a
4 changed files with 34 additions and 12 deletions

View File

@@ -38,7 +38,7 @@ class SimpleThreadScopeTests {
@Test
void getFromScope() throws Exception {
String name = "threadScopedObject";
String name = "removeNodeStatusScreen";
TestBean bean = this.applicationContext.getBean(name, TestBean.class);
assertThat(bean).isNotNull();
assertThat(this.applicationContext.getBean(name)).isSameAs(bean);
@@ -50,8 +50,8 @@ class SimpleThreadScopeTests {
void getMultipleInstances() throws Exception {
// Arrange
TestBean[] beans = new TestBean[2];
Thread thread1 = new Thread(() -> beans[0] = applicationContext.getBean("threadScopedObject", TestBean.class));
Thread thread2 = new Thread(() -> beans[1] = applicationContext.getBean("threadScopedObject", TestBean.class));
Thread thread1 = new Thread(() -> beans[0] = applicationContext.getBean("removeNodeStatusScreen", TestBean.class));
Thread thread2 = new Thread(() -> beans[1] = applicationContext.getBean("removeNodeStatusScreen", TestBean.class));
// Act
thread1.start();
thread2.start();