From ec0498643444b954672da51efa70c0109b7f0a69 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Thu, 6 Jun 2024 08:15:41 -0500 Subject: [PATCH] Fix to use a static threadPool, rather than one per each instance! --- .../tables/helpers/ActionTimeoutHelper.java | 7 +- .../helpers/ActionTimeoutHelperTest.java | 66 +++++++++++++++++-- 2 files changed, 65 insertions(+), 8 deletions(-) diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/ActionTimeoutHelper.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/ActionTimeoutHelper.java index 853e8a2b..f163ba07 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/ActionTimeoutHelper.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/ActionTimeoutHelper.java @@ -23,8 +23,10 @@ package com.kingsrook.qqq.backend.core.actions.tables.helpers; import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import com.kingsrook.qqq.backend.core.utils.PrefixedDefaultThreadFactory; /******************************************************************************* @@ -50,6 +52,9 @@ public class ActionTimeoutHelper private boolean didTimeout = false; + private static Integer CORE_THREADS = 10; + private static ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(CORE_THREADS, new PrefixedDefaultThreadFactory(ActionTimeoutHelper.class)); + /******************************************************************************* @@ -75,7 +80,7 @@ public class ActionTimeoutHelper return; } - future = Executors.newSingleThreadScheduledExecutor().schedule(() -> + future = scheduledExecutorService.schedule(() -> { didTimeout = true; runnable.run(); diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/ActionTimeoutHelperTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/ActionTimeoutHelperTest.java index f0fcf897..760fe309 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/ActionTimeoutHelperTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/ActionTimeoutHelperTest.java @@ -22,10 +22,19 @@ package com.kingsrook.qqq.backend.core.actions.tables.helpers; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import com.kingsrook.qqq.backend.core.BaseTest; import com.kingsrook.qqq.backend.core.utils.SleepUtils; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -35,7 +44,18 @@ import static org.junit.jupiter.api.Assertions.assertTrue; *******************************************************************************/ class ActionTimeoutHelperTest extends BaseTest { - boolean didCancel = false; + private static AtomicInteger cancelCount; + + + + /******************************************************************************* + ** + *******************************************************************************/ + @BeforeEach + void beforeEach() + { + cancelCount = new AtomicInteger(0); + } @@ -45,11 +65,10 @@ class ActionTimeoutHelperTest extends BaseTest @Test void testTimesOut() { - didCancel = false; ActionTimeoutHelper actionTimeoutHelper = new ActionTimeoutHelper(10, TimeUnit.MILLISECONDS, () -> doCancel()); actionTimeoutHelper.start(); SleepUtils.sleep(50, TimeUnit.MILLISECONDS); - assertTrue(didCancel); + assertEquals(1, cancelCount.get()); assertTrue(actionTimeoutHelper.getDidTimeout()); } @@ -61,25 +80,58 @@ class ActionTimeoutHelperTest extends BaseTest @Test void testGetsCancelled() { - didCancel = false; ActionTimeoutHelper actionTimeoutHelper = new ActionTimeoutHelper(100, TimeUnit.MILLISECONDS, () -> doCancel()); actionTimeoutHelper.start(); SleepUtils.sleep(10, TimeUnit.MILLISECONDS); actionTimeoutHelper.cancel(); - assertFalse(didCancel); + assertEquals(0, cancelCount.get()); SleepUtils.sleep(200, TimeUnit.MILLISECONDS); - assertFalse(didCancel); + assertEquals(0, cancelCount.get()); assertFalse(actionTimeoutHelper.getDidTimeout()); } + /******************************************************************************* + ** goal here is - confirm that we can have more threads running at same time + ** than we have threads allocated to the ActionTimeoutHelper's thread pool, + ** and they should all still get cancelled. + *******************************************************************************/ + @Test + void testManyThreads() throws InterruptedException, ExecutionException + { + int N = 50; + + ExecutorService executorService = Executors.newCachedThreadPool(); + List> futureList = new ArrayList<>(); + + for(int i = 0; i < N; i++) + { + System.out.println("Submitting: " + i); + futureList.add(executorService.submit(() -> + { + ActionTimeoutHelper actionTimeoutHelper = new ActionTimeoutHelper(10, TimeUnit.MILLISECONDS, () -> doCancel()); + actionTimeoutHelper.start(); + SleepUtils.sleep(1, TimeUnit.SECONDS); + })); + } + + for(Future future : futureList) + { + future.get(); + } + + assertEquals(N, cancelCount.get()); + } + + + /******************************************************************************* ** *******************************************************************************/ private void doCancel() { - didCancel = true; + cancelCount.getAndIncrement(); } } \ No newline at end of file