diff --git a/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/Hk2RequestScope.java b/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/Hk2RequestScope.java index e9437c458c..2d66c16792 100644 --- a/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/Hk2RequestScope.java +++ b/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/Hk2RequestScope.java @@ -139,7 +139,7 @@ public boolean contains(ForeignDescriptor provider) { */ @Override public void release() { - if (referenceCounter.decrementAndGet() < 1) { + if (referenceCounter.decrementAndGet() == 0) { try { ArrayList reverse = new ArrayList<>(store.keySet()); Collections.reverse(reverse); diff --git a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/process/internal/RequestScopeTest.java b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/process/internal/RequestScopeTest.java index d0488fa84d..6a875a84e7 100644 --- a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/process/internal/RequestScopeTest.java +++ b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/process/internal/RequestScopeTest.java @@ -17,6 +17,7 @@ package org.glassfish.jersey.tests.e2e.common.process.internal; import java.lang.reflect.Type; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; @@ -171,12 +172,67 @@ public void accept(Object o) { Assertions.assertEquals(987654321, instanceRelease.get()); } + @Test + public void testMultipleReleases() throws InterruptedException { + final RequestScope requestScope = new Hk2RequestScope(); + final AtomicBoolean passed = new AtomicBoolean(true); + final int CNT = 200; + Thread[] thread = new Thread[CNT]; + Hk2RequestScope.Instance instance = requestScope.runInScope(() -> { + final Hk2RequestScope.Instance internalInstance = (Hk2RequestScope.Instance) requestScope.current(); + for (int index = 1; index != CNT; index++) { + TestProvider testProvider = new TestProvider(String.valueOf(index)) { + @Override + public int hashCode() { + return super.hashCode() + Integer.parseInt(id); + } + }; + final ForeignDescriptor fd = ForeignDescriptor.wrap(testProvider, new Consumer() { + @Override + public void accept(Object o) { + // noop + } + }); + internalInstance.put(fd, String.valueOf(index)); + + for (int i = 0; i != CNT; i++) { + thread[i] = new Thread(new Runnable() { + @Override + public void run() { + final long waitTime = (int) (Math.random() * 5 + 1) * 10L; + try { + Thread.sleep(waitTime); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + try { + internalInstance.release(); + } catch (Throwable throwable) { + passed.set(false); + } + } + }); + } + for (int i = 0; i != CNT; i++) { + thread[i].start(); + } + } + return internalInstance; + }); + + for (int i = 0; i != CNT; i++) { + thread[i].join(); + } + + Assertions.assertTrue(passed.get()); + } + /** * Test request scope inhabitant. */ public static class TestProvider extends AbstractActiveDescriptor { - private final String id; + public final String id; public TestProvider(final String id) { super();