提交 9450809a 编写于 作者: oldratlee's avatar oldratlee 🔥

add DisableInheritableForkJoinWorkerThreadFactory and unit test

上级 ef6fec36
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();
}
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;
}
}
......@@ -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();
}
......@@ -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;
......
......@@ -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 {
......
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}.
* <p>
* 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() {
}
}
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
}
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<String?>()
ttl.set(hello)
val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!!
try {
val ttl = TransmittableThreadLocal<String?>()
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<String?>()
ttl.set(hello)
try {
val ttl = TransmittableThreadLocal<String?>()
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<String?>() {
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<String>() {
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<String>() {
override fun initialValue(): String = defaultValue
override fun childValue(parentValue: String): String = initialValue()
try {
val ttl = object : TransmittableThreadLocal<String>() {
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<String?>()
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<String?>() {
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<String?>()
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<String?>() {
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<String>() {
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<String>() {
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<String>() {
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()
}
}
}
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<Executor>(null))
}
}
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))
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册