diff --git a/src/main/java/com/alibaba/ttl/threadpool/DisableInheritableForkJoinWorkerThreadFactory.java b/src/main/java/com/alibaba/ttl/threadpool/DisableInheritableForkJoinWorkerThreadFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..00759c56cb62e9746bb2b63fc7745396cfdeab4d --- /dev/null +++ b/src/main/java/com/alibaba/ttl/threadpool/DisableInheritableForkJoinWorkerThreadFactory.java @@ -0,0 +1,18 @@ +package com.alibaba.ttl.threadpool; + +import javax.annotation.Nonnull; +import java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory; + +/** + * Disable inheritable {@link ForkJoinWorkerThreadFactory}. + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @since 2.10.1 + */ +public interface DisableInheritableForkJoinWorkerThreadFactory extends ForkJoinWorkerThreadFactory { + /** + * Unwrap {@link DisableInheritableThreadFactory} to the original/underneath one. + */ + @Nonnull + ForkJoinWorkerThreadFactory unwrap(); +} diff --git a/src/main/java/com/alibaba/ttl/threadpool/DisableInheritableForkJoinWorkerThreadFactoryWrapper.java b/src/main/java/com/alibaba/ttl/threadpool/DisableInheritableForkJoinWorkerThreadFactoryWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..c080d237231c8fc02eb2df3828243cc80291804f --- /dev/null +++ b/src/main/java/com/alibaba/ttl/threadpool/DisableInheritableForkJoinWorkerThreadFactoryWrapper.java @@ -0,0 +1,36 @@ +package com.alibaba.ttl.threadpool; + +import com.alibaba.ttl.TransmittableThreadLocal; + +import javax.annotation.Nonnull; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory; +import java.util.concurrent.ForkJoinWorkerThread; + +/** + * @author Jerry Lee (oldratlee at gmail dot com) + * @since 2.10.1 + */ +class DisableInheritableForkJoinWorkerThreadFactoryWrapper implements DisableInheritableForkJoinWorkerThreadFactory { + final ForkJoinWorkerThreadFactory threadFactory; + + public DisableInheritableForkJoinWorkerThreadFactoryWrapper(@Nonnull ForkJoinWorkerThreadFactory threadFactory) { + this.threadFactory = threadFactory; + } + + @Override + public ForkJoinWorkerThread newThread(ForkJoinPool pool) { + final Object backup = TransmittableThreadLocal.Transmitter.clear(); + try { + return threadFactory.newThread(pool); + } finally { + TransmittableThreadLocal.Transmitter.restore(backup); + } + } + + @Nonnull + @Override + public ForkJoinWorkerThreadFactory unwrap() { + return threadFactory; + } +} diff --git a/src/main/java/com/alibaba/ttl/threadpool/DisableInheritableThreadFactory.java b/src/main/java/com/alibaba/ttl/threadpool/DisableInheritableThreadFactory.java index edfb6646f522986292cb558febfb19df1662b6bd..091b64663b9e74dcf30b56d327420ef19cf7c2eb 100644 --- a/src/main/java/com/alibaba/ttl/threadpool/DisableInheritableThreadFactory.java +++ b/src/main/java/com/alibaba/ttl/threadpool/DisableInheritableThreadFactory.java @@ -4,11 +4,16 @@ import javax.annotation.Nonnull; import java.util.concurrent.ThreadFactory; /** - * Disable inheritable thread factory. + * Disable inheritable {@link ThreadFactory}. * + * @author Jerry Lee (oldratlee at gmail dot com) * @see ThreadFactory + * @since 2.10.0 */ public interface DisableInheritableThreadFactory extends ThreadFactory { + /** + * Unwrap {@link DisableInheritableThreadFactory} to the original/underneath one. + */ @Nonnull ThreadFactory unwrap(); } diff --git a/src/main/java/com/alibaba/ttl/threadpool/DisableInheritableThreadFactoryWrapper.java b/src/main/java/com/alibaba/ttl/threadpool/DisableInheritableThreadFactoryWrapper.java index 8aba85fb9aad105cac2fe5d6ac6548b9b9c8d365..3b548257af28a14a1582ebf2f8dc3ae37a225b78 100644 --- a/src/main/java/com/alibaba/ttl/threadpool/DisableInheritableThreadFactoryWrapper.java +++ b/src/main/java/com/alibaba/ttl/threadpool/DisableInheritableThreadFactoryWrapper.java @@ -5,6 +5,10 @@ import com.alibaba.ttl.TransmittableThreadLocal; import javax.annotation.Nonnull; import java.util.concurrent.ThreadFactory; +/** + * @author Jerry Lee (oldratlee at gmail dot com) + * @since 2.10.0 + */ class DisableInheritableThreadFactoryWrapper implements DisableInheritableThreadFactory { final ThreadFactory threadFactory; diff --git a/src/main/java/com/alibaba/ttl/threadpool/TtlExecutors.java b/src/main/java/com/alibaba/ttl/threadpool/TtlExecutors.java index 502435c7a6bcfc45bb4b2ea2ee7a7b6b8b721e78..17cfaf260190a33fe76e4f88be2a3631de740203 100644 --- a/src/main/java/com/alibaba/ttl/threadpool/TtlExecutors.java +++ b/src/main/java/com/alibaba/ttl/threadpool/TtlExecutors.java @@ -25,6 +25,8 @@ import java.util.concurrent.*; * @see java.util.concurrent.Executors * @see java.util.concurrent.CompletionService * @see java.util.concurrent.ExecutorCompletionService + * @see ThreadFactory + * @see Executors#defaultThreadFactory() * @since 0.9.0 */ public final class TtlExecutors { diff --git a/src/main/java/com/alibaba/ttl/threadpool/TtlForkJoinPool.java b/src/main/java/com/alibaba/ttl/threadpool/TtlForkJoinPool.java new file mode 100644 index 0000000000000000000000000000000000000000..36554871c86febdc0866125d6f28e8fa17ac410f --- /dev/null +++ b/src/main/java/com/alibaba/ttl/threadpool/TtlForkJoinPool.java @@ -0,0 +1,70 @@ +package com.alibaba.ttl.threadpool; + +import javax.annotation.Nullable; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory; + +/** + * Factory Utils for getting TTL wrapper of {@link ForkJoinWorkerThreadFactory}. + *

+ * all method is {@code null}-safe, when input parameter(eg: {@link ForkJoinWorkerThreadFactory}) is {@code null}, return {@code null}. + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @see ForkJoinPool + * @see ForkJoinWorkerThreadFactory + * @see ForkJoinPool#defaultForkJoinWorkerThreadFactory + * @since 2.10.1 + */ +public class TtlForkJoinPool { + /** + * Wrapper of {@link ForkJoinWorkerThreadFactory}, disable inheritable. + * + * @param threadFactory input thread factory + * @see DisableInheritableForkJoinWorkerThreadFactory + * @since 2.10.1 + */ + @Nullable + public static ForkJoinWorkerThreadFactory getDisableInheritableForkJoinWorkerThreadFactory(@Nullable ForkJoinWorkerThreadFactory threadFactory) { + if (threadFactory == null || isDisableInheritableForkJoinWorkerThreadFactory(threadFactory)) + return threadFactory; + + return new DisableInheritableForkJoinWorkerThreadFactoryWrapper(threadFactory); + } + + /** + * Wrapper of {@link ForkJoinPool#defaultForkJoinWorkerThreadFactory}, disable inheritable. + * + * @see #getDisableInheritableForkJoinWorkerThreadFactory(ForkJoinWorkerThreadFactory) + * @since 2.10.1 + */ + @Nullable + public static ForkJoinWorkerThreadFactory getDefaultDisableInheritableForkJoinWorkerThreadFactory() { + return getDisableInheritableForkJoinWorkerThreadFactory(ForkJoinPool.defaultForkJoinWorkerThreadFactory); + } + + /** + * check the {@link ForkJoinWorkerThreadFactory} is {@link DisableInheritableForkJoinWorkerThreadFactory} or not. + * + * @see DisableInheritableForkJoinWorkerThreadFactory + * @since 2.10.1 + */ + public static boolean isDisableInheritableForkJoinWorkerThreadFactory(@Nullable ForkJoinWorkerThreadFactory threadFactory) { + return threadFactory instanceof DisableInheritableForkJoinWorkerThreadFactory; + } + + /** + * Unwrap {@link DisableInheritableForkJoinWorkerThreadFactory} to the original/underneath one. + * + * @see DisableInheritableForkJoinWorkerThreadFactory + * @since 2.10.1 + */ + @Nullable + public static ForkJoinWorkerThreadFactory unwrap(@Nullable ForkJoinWorkerThreadFactory threadFactory) { + if (!isDisableInheritableForkJoinWorkerThreadFactory(threadFactory)) return threadFactory; + + return ((DisableInheritableForkJoinWorkerThreadFactoryWrapper) threadFactory).unwrap(); + } + + private TtlForkJoinPool() { + } +} diff --git a/src/test/java/com/alibaba/support/junit/conditional/IsAgentRunOrBelowJava7.kt b/src/test/java/com/alibaba/support/junit/conditional/IsAgentRunOrBelowJava7.kt new file mode 100644 index 0000000000000000000000000000000000000000..494a088efc1bcd9c420ef03a018c2d189316462b --- /dev/null +++ b/src/test/java/com/alibaba/support/junit/conditional/IsAgentRunOrBelowJava7.kt @@ -0,0 +1,10 @@ +package com.alibaba.support.junit.conditional + +import com.alibaba.support.junit.conditional.ConditionalIgnoreRule.IgnoreCondition + +/** + * @see [Getting Java version at runtime](https://stackoverflow.com/a/23706899/922688) + */ +class IsAgentRunOrBelowJava7 : IgnoreCondition { + override fun isSatisfied(): Boolean = IsAgentRun().isSatisfied || BelowJava7().isSatisfied +} diff --git a/src/test/java/com/alibaba/ttl/InheritableTest.kt b/src/test/java/com/alibaba/ttl/InheritableTest.kt index 4d13b24ed814b3a7eb6abd3defd243214c8cc1d3..8e24fd0152bab542d795bf024d9f7307e9a6e5c3 100644 --- a/src/test/java/com/alibaba/ttl/InheritableTest.kt +++ b/src/test/java/com/alibaba/ttl/InheritableTest.kt @@ -1,9 +1,12 @@ package com.alibaba.ttl +import com.alibaba.support.junit.conditional.BelowJava7 import com.alibaba.support.junit.conditional.ConditionalIgnoreRule import com.alibaba.support.junit.conditional.ConditionalIgnoreRule.ConditionalIgnore import com.alibaba.support.junit.conditional.IsAgentRun +import com.alibaba.support.junit.conditional.IsAgentRunOrBelowJava7 import com.alibaba.ttl.threadpool.TtlExecutors +import com.alibaba.ttl.threadpool.TtlForkJoinPool import org.junit.Assert.assertEquals import org.junit.Assert.assertNull import org.junit.Rule @@ -11,6 +14,7 @@ import org.junit.Test import java.util.* import java.util.concurrent.Callable import java.util.concurrent.Executors +import java.util.concurrent.ForkJoinPool private const val hello = "hello" private val defaultValue = "${Date()} ${Math.random()}" @@ -20,110 +24,245 @@ class InheritableTest { @JvmField val rule = ConditionalIgnoreRule() + // =================================================== + // Executors + // =================================================== + @Test - fun inheritable() { + fun inheritable_Executors() { val threadPool = Executors.newCachedThreadPool() - val ttl = TransmittableThreadLocal() - ttl.set(hello) - - val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!! + try { + val ttl = TransmittableThreadLocal() + ttl.set(hello) - // get "hello" value is transmitted by InheritableThreadLocal function! - // NOTE: newCachedThreadPool create thread lazily - assertEquals(hello, threadPool.submit(callable).get()) + val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!! - // current thread's TTL must be exist when using DisableInheritableThreadFactory - assertEquals(hello, ttl.get()) + // get "hello" value is transmitted by InheritableThreadLocal function! + // NOTE: Executors.newCachedThreadPool create thread lazily + assertEquals(hello, threadPool.submit(callable).get()) - threadPool.shutdown() + // current thread's TTL must be exist + assertEquals(hello, ttl.get()) + } finally { + threadPool.shutdown() + } } @Test @ConditionalIgnore(condition = IsAgentRun::class) - fun disableDisableInheritableThreadFactory() { + fun disableInheritable_Executors_DisableInheritableThreadFactory() { val threadPool = Executors.newCachedThreadPool(TtlExecutors.getDefaultDisableInheritableThreadFactory()) - val ttl = TransmittableThreadLocal() - ttl.set(hello) + try { + val ttl = TransmittableThreadLocal() + ttl.set(hello) - val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!! + val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!! + + // when ttl agent is loaded, Callable is wrapped when submit, + // so here value is "hello" transmitted by TtlCallable wrapper + // IGNORE this test case when TtlAgent is run. + assertNull(threadPool.submit(callable).get()) + + // current thread's TTL must be exist when using DisableInheritableThreadFactory + assertEquals(hello, ttl.get()) + } finally { + threadPool.shutdown() + } + } + + @Test + @ConditionalIgnore(condition = IsAgentRun::class) + fun disableInheritable_Executors_TtlDisableInheritableWithInitialValue() { + val threadPool = Executors.newCachedThreadPool() + try { + val ttl = object : TransmittableThreadLocal() { + override fun childValue(parentValue: String?): String? = initialValue() + } + ttl.set(hello) - // when ttl agent is loaded, Callable is wrapped when submit, - // so here value is "hello" transmitted by TtlCallable wrapper - // IGNORE this test case when TtlAgent is run. - assertNull(threadPool.submit(callable).get()) + val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!! - // current thread's TTL must be exist when using DisableInheritableThreadFactory - assertEquals(hello, ttl.get()) + // when ttl agent is loaded, Callable is wrapped when submit, + // so here value is "hello" transmitted by TtlCallable wrapper + // IGNORE this test case when TtlAgent is run. + assertNull(threadPool.submit(callable).get()) - threadPool.shutdown() + // current thread's TTL must be exist + assertEquals(hello, ttl.get()) + } finally { + threadPool.shutdown() + } } + @Test + @ConditionalIgnore(condition = IsAgentRun::class) + fun disableInheritable_Executors_TtlDefaultValue_TtlDisableInheritableWithInitialValue() { + val threadPool = Executors.newCachedThreadPool() + try { + val ttl = object : TransmittableThreadLocal() { + override fun initialValue(): String = defaultValue + override fun childValue(parentValue: String): String = initialValue() + } + ttl.set(hello) + + val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!! + + // when ttl agent is loaded, Callable is wrapped when submit, + // so here value is "hello" transmitted by TtlCallable wrapper + // IGNORE this test case when TtlAgent is run. + assertEquals(defaultValue, threadPool.submit(callable).get()) + + // current thread's TTL must be exist when using DisableInheritableThreadFactory + assertEquals(hello, ttl.get()) + } finally { + threadPool.shutdown() + } + } @Test @ConditionalIgnore(condition = IsAgentRun::class) - fun disableDisableInheritableThreadFactory_TTL_with_initialValue() { + fun disableInheritable_Executors_TtlDefaultValue_DisableInheritableThreadFactory_TtlWithInitialValue() { val threadPool = Executors.newCachedThreadPool(TtlExecutors.getDefaultDisableInheritableThreadFactory()) - val ttl = object : TransmittableThreadLocal() { - override fun initialValue(): String = defaultValue - override fun childValue(parentValue: String): String = initialValue() + try { + val ttl = object : TransmittableThreadLocal() { + override fun initialValue(): String = defaultValue + override fun childValue(parentValue: String): String = initialValue() + } + ttl.set(hello) + + val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!! + + // when ttl agent is loaded, Callable is wrapped when submit, + // so here value is "hello" transmitted by TtlCallable wrapper + // IGNORE this test case when TtlAgent is run. + assertEquals(defaultValue, threadPool.submit(callable).get()) + + // current thread's TTL must be exist when using DisableInheritableThreadFactory + assertEquals(hello, ttl.get()) + } finally { + threadPool.shutdown() } - ttl.set(hello) + } + + // =================================================== + // ForkJoinPool + // =================================================== - val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!! + @Test + @ConditionalIgnore(condition = BelowJava7::class) + fun inheritable_ForkJoinPool() { + val threadPool = ForkJoinPool(4) + try { + val ttl = TransmittableThreadLocal() + ttl.set(hello) - // when ttl agent is loaded, Callable is wrapped when submit, - // so here value is "hello" transmitted by TtlCallable wrapper - // IGNORE this test case when TtlAgent is run. - assertEquals(defaultValue, threadPool.submit(callable).get()) + val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!! - // current thread's TTL must be exist when using DisableInheritableThreadFactory - assertEquals(hello, ttl.get()) + // get "hello" value is transmitted by InheritableThreadLocal function! + // NOTE: Executors.newCachedThreadPool create thread lazily + assertEquals(hello, threadPool.submit(callable).get()) - threadPool.shutdown() + // current thread's TTL must be exist + assertEquals(hello, ttl.get()) + } finally { + threadPool.shutdown() + } } @Test - @ConditionalIgnore(condition = IsAgentRun::class) - fun disableInheritable() { - val threadPool = Executors.newCachedThreadPool() - val ttl = object : TransmittableThreadLocal() { - override fun childValue(parentValue: String?): String? = initialValue() + @ConditionalIgnore(condition = IsAgentRunOrBelowJava7::class) + fun disableInheritable_ForkJoinPool_DisableInheritableForkJoinWorkerThreadFactory() { + val threadPool = ForkJoinPool(4, TtlForkJoinPool.getDefaultDisableInheritableForkJoinWorkerThreadFactory(), null, false) + try { + val ttl = TransmittableThreadLocal() + ttl.set(hello) + + val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!! + + // when ttl agent is loaded, Callable is wrapped when submit, + // so here value is "hello" transmitted by TtlCallable wrapper + // IGNORE this test case when TtlAgent is run. + assertNull(threadPool.submit(callable).get()) + + // current thread's TTL must be exist when using DisableInheritableForkJoinWorkerThreadFactory + assertEquals(hello, ttl.get()) + } finally { + threadPool.shutdown() } - ttl.set(hello) + } - val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!! + @Test + @ConditionalIgnore(condition = IsAgentRunOrBelowJava7::class) + fun disableInheritable_ForkJoinPool_TtlDisableInheritableWithInitialValue() { + val threadPool = ForkJoinPool(4) + try { + val ttl = object : TransmittableThreadLocal() { + override fun childValue(parentValue: String?): String? = initialValue() + } + ttl.set(hello) - // when ttl agent is loaded, Callable is wrapped when submit, - // so here value is "hello" transmitted by TtlCallable wrapper - // IGNORE this test case when TtlAgent is run. - assertNull(threadPool.submit(callable).get()) + val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!! - // current thread's TTL must be exist when using DisableInheritableThreadFactory - assertEquals(hello, ttl.get()) + // when ttl agent is loaded, Callable is wrapped when submit, + // so here value is "hello" transmitted by TtlCallable wrapper + // IGNORE this test case when TtlAgent is run. + assertNull(threadPool.submit(callable).get()) - threadPool.shutdown() + // current thread's TTL must be exist + assertEquals(hello, ttl.get()) + } finally { + threadPool.shutdown() + } } @Test - @ConditionalIgnore(condition = IsAgentRun::class) - fun disableInheritable_TTL_with_initialValue() { - val threadPool = Executors.newCachedThreadPool() - val ttl = object : TransmittableThreadLocal() { - override fun initialValue(): String = defaultValue - override fun childValue(parentValue: String): String = initialValue() + @ConditionalIgnore(condition = IsAgentRunOrBelowJava7::class) + fun disableInheritable_ForkJoinPool_TtlDefaultValue_TtlDisableInheritableWithInitialValue() { + val threadPool = ForkJoinPool(4) + try { + val ttl = object : TransmittableThreadLocal() { + override fun initialValue(): String = defaultValue + override fun childValue(parentValue: String): String = initialValue() + } + ttl.set(hello) + + val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!! + + // when ttl agent is loaded, Callable is wrapped when submit, + // so here value is "hello" transmitted by TtlCallable wrapper + // IGNORE this test case when TtlAgent is run. + assertEquals(defaultValue, threadPool.submit(callable).get()) + + // current thread's TTL must be exist + assertEquals(hello, ttl.get()) + } finally { + threadPool.shutdown() } - ttl.set(hello) + } - val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!! + @Test + @ConditionalIgnore(condition = IsAgentRunOrBelowJava7::class) + fun disableInheritable_ForkJoinPool_TtlDefaultValue_DisableInheritableForkJoinWorkerThreadFactory_TtlWithInitialValue() { + val threadPool = ForkJoinPool(4, TtlForkJoinPool.getDefaultDisableInheritableForkJoinWorkerThreadFactory(), null, false) + try { + val ttl = object : TransmittableThreadLocal() { + override fun initialValue(): String = defaultValue + override fun childValue(parentValue: String): String = initialValue() + } + ttl.set(hello) - // when ttl agent is loaded, Callable is wrapped when submit, - // so here value is "hello" transmitted by TtlCallable wrapper - // IGNORE this test case when TtlAgent is run. - assertEquals(defaultValue, threadPool.submit(callable).get()) + val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!! - // current thread's TTL must be exist when using DisableInheritableThreadFactory - assertEquals(hello, ttl.get()) + // when ttl agent is loaded, Callable is wrapped when submit, + // so here value is "hello" transmitted by TtlCallable wrapper + // IGNORE this test case when TtlAgent is run. + assertEquals(defaultValue, threadPool.submit(callable).get()) - threadPool.shutdown() + // current thread's TTL must be exist when using DisableInheritableForkJoinWorkerThreadFactory + assertEquals(hello, ttl.get()) + } finally { + threadPool.shutdown() + } } + } diff --git a/src/test/java/com/alibaba/ttl/threadpool/TtlExecutorsTest.kt b/src/test/java/com/alibaba/ttl/threadpool/TtlExecutorsTest.kt index 543b967976947d515f811527361768d0a1bfbb6b..44c61bfaa86e6a26ffb27cacf8c3935ea3f3852e 100644 --- a/src/test/java/com/alibaba/ttl/threadpool/TtlExecutorsTest.kt +++ b/src/test/java/com/alibaba/ttl/threadpool/TtlExecutorsTest.kt @@ -1,54 +1,59 @@ package com.alibaba.ttl.threadpool -import com.alibaba.support.junit.conditional.ConditionalIgnoreRule -import com.alibaba.support.junit.conditional.ConditionalIgnoreRule.ConditionalIgnore -import com.alibaba.support.junit.conditional.IsAgentRun +import com.alibaba.noTtlAgentRun import com.alibaba.ttl.threadpool.TtlExecutors.* import org.junit.Assert.* -import org.junit.Rule import org.junit.Test +import java.util.concurrent.Executor import java.util.concurrent.Executors.newScheduledThreadPool +import java.util.concurrent.ThreadFactory /** * @author Jerry Lee (oldratlee at gmail dot com) */ class TtlExecutorsTest { - @Rule - @JvmField - val rule = ConditionalIgnoreRule() @Test - @ConditionalIgnore(condition = IsAgentRun::class) - fun test_common() { + fun test_common_executors() { val newScheduledThreadPool = newScheduledThreadPool(3) getTtlExecutor(newScheduledThreadPool).let { - assertTrue(it is ExecutorTtlWrapper) - assertTrue(isTtlWrapper(it)) + if (noTtlAgentRun()) assertTrue(it is ExecutorTtlWrapper) + assertEquals(noTtlAgentRun(), isTtlWrapper(it)) assertSame(newScheduledThreadPool, unwrap(it)) } getTtlExecutorService(newScheduledThreadPool).let { - assertTrue(it is ExecutorServiceTtlWrapper) - assertTrue(isTtlWrapper(it)) + if (noTtlAgentRun()) assertTrue(it is ExecutorServiceTtlWrapper) + assertEquals(noTtlAgentRun(), isTtlWrapper(it)) assertSame(newScheduledThreadPool, unwrap(it)) } getTtlScheduledExecutorService(newScheduledThreadPool).let { - assertTrue(it is ScheduledExecutorServiceTtlWrapper) - assertTrue(isTtlWrapper(it)) + if (noTtlAgentRun()) assertTrue(it is ScheduledExecutorServiceTtlWrapper) + assertEquals(noTtlAgentRun(), isTtlWrapper(it)) assertSame(newScheduledThreadPool, unwrap(it)) } + + val threadFactory = ThreadFactory { Thread(it) } + getDisableInheritableThreadFactory(threadFactory).let { + assertTrue(it is DisableInheritableThreadFactory) + assertTrue(isDisableInheritableThreadFactory(it)) + + assertSame(threadFactory, unwrap(it)) + } } @Test - fun test_null() { + fun test_null_executors() { assertNull(getTtlExecutor(null)) assertNull(getTtlExecutorService(null)) assertNull(getTtlScheduledExecutorService(null)) assertFalse(isTtlWrapper(null)) - assertNull(unwrap(null)) + assertNull(unwrap(null)) } + + } diff --git a/src/test/java/com/alibaba/ttl/threadpool/TtlForkJoinPoolTest.kt b/src/test/java/com/alibaba/ttl/threadpool/TtlForkJoinPoolTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..6e5acbd8072ba876768d3f5b8cca4be4ec484859 --- /dev/null +++ b/src/test/java/com/alibaba/ttl/threadpool/TtlForkJoinPoolTest.kt @@ -0,0 +1,32 @@ +package com.alibaba.ttl.threadpool + +import com.alibaba.support.junit.conditional.BelowJava7 +import com.alibaba.support.junit.conditional.ConditionalIgnoreRule +import org.junit.Assert.* +import org.junit.Rule +import org.junit.Test +import java.util.concurrent.ForkJoinPool + +class TtlForkJoinPoolTest { + @Rule + @JvmField + val rule = ConditionalIgnoreRule() + + @Test + @ConditionalIgnoreRule.ConditionalIgnore(condition = BelowJava7::class) + fun test_common_ForkJoinPool() { + TtlForkJoinPool.getDefaultDisableInheritableForkJoinWorkerThreadFactory().let { + assertTrue(it is DisableInheritableForkJoinWorkerThreadFactory) + assertTrue(TtlForkJoinPool.isDisableInheritableForkJoinWorkerThreadFactory(it)) + + assertSame(ForkJoinPool.defaultForkJoinWorkerThreadFactory, TtlForkJoinPool.unwrap(it)) + } + } + + @Test + @ConditionalIgnoreRule.ConditionalIgnore(condition = BelowJava7::class) + fun test_null_ForkJoinPool() { + assertFalse(TtlForkJoinPool.isDisableInheritableForkJoinWorkerThreadFactory(null)) + assertNull(TtlForkJoinPool.unwrap(null as? ForkJoinPool.ForkJoinWorkerThreadFactory)) + } +}