Fix tests for executorService.shutdown()

Even if `Executors.newSingleThreadExecutor()` returns a `FinalizableDelegatedExecutorService`,
an instance is kept in the memory until JVM exists.
That may lead to memory leak since we have a lot of threads in memory.

(cherry picked from commit fdac8f1634)
This commit is contained in:
Artem Bilan
2024-08-13 15:57:25 -04:00
committed by Spring Builds
parent 6a7581e6cc
commit ec2cfeb9b8
13 changed files with 132 additions and 78 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 the original author or authors.
* Copyright 2014-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@@ -88,8 +89,9 @@ class AggregatorWithRedisLocksTests implements RedisContainerTest {
@Test
void testLockSingleGroup() throws Exception {
this.releaseStrategy.reset(1);
Executors.newSingleThreadExecutor().execute(asyncSend("foo", 1, 1));
Executors.newSingleThreadExecutor().execute(asyncSend("bar", 2, 1));
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(asyncSend("foo", 1, 1));
executorService.execute(asyncSend("bar", 2, 1));
assertThat(this.releaseStrategy.latch2.await(10, TimeUnit.SECONDS)).isTrue();
assertThat(this.template.keys("aggregatorWithRedisLocksTests:*")).hasSize(1);
this.releaseStrategy.latch1.countDown();
@@ -98,17 +100,19 @@ class AggregatorWithRedisLocksTests implements RedisContainerTest {
this.assertNoLocksAfterTest();
assertThat(this.exception)
.as("Unexpected exception:" + (this.exception != null ? this.exception.toString() : "")).isNull();
executorService.shutdown();
}
@Test
void testLockThreeGroups() throws Exception {
this.releaseStrategy.reset(3);
Executors.newSingleThreadExecutor().execute(asyncSend("foo", 1, 1));
Executors.newSingleThreadExecutor().execute(asyncSend("bar", 2, 1));
Executors.newSingleThreadExecutor().execute(asyncSend("foo", 1, 2));
Executors.newSingleThreadExecutor().execute(asyncSend("bar", 2, 2));
Executors.newSingleThreadExecutor().execute(asyncSend("foo", 1, 3));
Executors.newSingleThreadExecutor().execute(asyncSend("bar", 2, 3));
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(asyncSend("foo", 1, 1));
executorService.execute(asyncSend("bar", 2, 1));
executorService.execute(asyncSend("foo", 1, 2));
executorService.execute(asyncSend("bar", 2, 2));
executorService.execute(asyncSend("foo", 1, 3));
executorService.execute(asyncSend("bar", 2, 3));
assertThat(this.releaseStrategy.latch2.await(10, TimeUnit.SECONDS)).isTrue();
assertThat(this.template.keys("aggregatorWithRedisLocksTests:*")).hasSize(3);
this.releaseStrategy.latch1.countDown();
@@ -121,13 +125,15 @@ class AggregatorWithRedisLocksTests implements RedisContainerTest {
this.assertNoLocksAfterTest();
assertThat(this.exception)
.as("Unexpected exception:" + (this.exception != null ? this.exception.toString() : "")).isNull();
executorService.shutdown();
}
@RepeatedTest(10)
void testDistributedAggregator() throws Exception {
this.releaseStrategy.reset(1);
Executors.newSingleThreadExecutor().execute(asyncSend("foo", 1, 1));
Executors.newSingleThreadExecutor().execute(() -> {
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(asyncSend("foo", 1, 1));
executorService.execute(() -> {
try {
in2.send(new GenericMessage<>("bar", stubHeaders(2, 2, 1)));
}
@@ -143,6 +149,7 @@ class AggregatorWithRedisLocksTests implements RedisContainerTest {
this.assertNoLocksAfterTest();
assertThat(this.exception)
.as("Unexpected exception:" + (this.exception != null ? this.exception.toString() : "")).isNull();
executorService.shutdown();
}
private void assertNoLocksAfterTest() throws Exception {

View File

@@ -228,7 +228,8 @@ class RedisLockRegistryTests implements RedisContainerTest {
lock1.lockInterruptibly();
final AtomicBoolean locked = new AtomicBoolean();
final CountDownLatch latch = new CountDownLatch(1);
Future<Object> result = Executors.newSingleThreadExecutor().submit(() -> {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<Object> result = executorService.submit(() -> {
Lock lock2 = registry.obtain("foo");
locked.set(lock2.tryLock(200, TimeUnit.MILLISECONDS));
latch.countDown();
@@ -249,6 +250,7 @@ class RedisLockRegistryTests implements RedisContainerTest {
registry.expireUnusedOlderThan(-1000);
assertThat(getRedisLockRegistryLocks(registry)).isEmpty();
registry.destroy();
executorService.shutdown();
}
@ParameterizedTest
@@ -263,7 +265,8 @@ class RedisLockRegistryTests implements RedisContainerTest {
CountDownLatch latch3 = new CountDownLatch(1);
lock1.lockInterruptibly();
assertThat(getRedisLockRegistryLocks(registry)).hasSize(1);
Executors.newSingleThreadExecutor().execute(() -> {
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(() -> {
Lock lock2 = registry.obtain("foo");
try {
latch1.countDown();
@@ -289,6 +292,7 @@ class RedisLockRegistryTests implements RedisContainerTest {
registry.expireUnusedOlderThan(-1000);
assertThat(getRedisLockRegistryLocks(registry)).isEmpty();
registry.destroy();
executorService.shutdown();
}
@ParameterizedTest
@@ -305,7 +309,8 @@ class RedisLockRegistryTests implements RedisContainerTest {
CountDownLatch latch3 = new CountDownLatch(1);
lock1.lockInterruptibly();
assertThat(getRedisLockRegistryLocks(registry1)).hasSize(1);
Executors.newSingleThreadExecutor().execute(() -> {
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(() -> {
Lock lock2 = registry2.obtain("foo");
try {
latch1.countDown();
@@ -340,6 +345,7 @@ class RedisLockRegistryTests implements RedisContainerTest {
assertThat(getRedisLockRegistryLocks(registry2)).isEmpty();
registry1.destroy();
registry2.destroy();
executorService.shutdown();
}
@ParameterizedTest
@@ -351,7 +357,8 @@ class RedisLockRegistryTests implements RedisContainerTest {
lock.lockInterruptibly();
AtomicBoolean locked = new AtomicBoolean();
CountDownLatch latch = new CountDownLatch(1);
Future<Object> result = Executors.newSingleThreadExecutor().submit(() -> {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<Object> result = executorService.submit(() -> {
try {
lock.unlock();
}
@@ -370,6 +377,7 @@ class RedisLockRegistryTests implements RedisContainerTest {
registry.expireUnusedOlderThan(-1000);
assertThat(getRedisLockRegistryLocks(registry)).isEmpty();
registry.destroy();
executorService.shutdown();
}
@ParameterizedTest
@@ -481,7 +489,8 @@ class RedisLockRegistryTests implements RedisContainerTest {
Long expire = getExpire(registry, "foo");
Future<Object> result = Executors.newSingleThreadExecutor().submit(() -> {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<Object> result = executorService.submit(() -> {
Lock lock2 = registry.obtain("foo");
assertThat(lock2.tryLock()).isFalse();
return null;
@@ -490,6 +499,7 @@ class RedisLockRegistryTests implements RedisContainerTest {
assertThat(getExpire(registry, "foo")).isEqualTo(expire);
lock.unlock();
registry.destroy();
executorService.shutdown();
}
@ParameterizedTest