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

disable ttl inheritable for thread created by thread pool #100

- add DisableInheritableThreadFactory wrapper in TtlExecutors
- add Inheritable unit test
上级 08946197
package com.alibaba.ttl.threadpool;
import javax.annotation.Nonnull;
import java.util.concurrent.ThreadFactory;
/**
* Disable inheritable thread factory.
*
* @see ThreadFactory
*/
public interface DisableInheritableThreadFactory extends ThreadFactory {
@Nonnull
ThreadFactory unwrap();
}
package com.alibaba.ttl.threadpool;
import com.alibaba.ttl.TransmittableThreadLocal;
import javax.annotation.Nonnull;
import java.util.concurrent.ThreadFactory;
class DisableInheritableThreadFactoryWrapper implements DisableInheritableThreadFactory {
final ThreadFactory threadFactory;
public DisableInheritableThreadFactoryWrapper(@Nonnull ThreadFactory threadFactory) {
this.threadFactory = threadFactory;
}
@Override
public Thread newThread(Runnable r) {
final Object backup = TransmittableThreadLocal.Transmitter.clear();
try {
return threadFactory.newThread(r);
} finally {
TransmittableThreadLocal.Transmitter.restore(backup);
}
}
@Nonnull
@Override
public ThreadFactory unwrap() {
return threadFactory;
}
}
......@@ -4,9 +4,7 @@ import com.alibaba.ttl.TransmittableThreadLocal;
import com.alibaba.ttl.threadpool.agent.TtlAgent;
import javax.annotation.Nullable;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.*;
/**
* Factory Utils for getting TTL wrapper of jdk executors.
......@@ -84,7 +82,7 @@ public final class TtlExecutors {
* @since 2.8.0
*/
public static <T extends Executor> boolean isTtlWrapper(@Nullable T executor) {
return (executor instanceof ExecutorTtlWrapper);
return executor instanceof ExecutorTtlWrapper;
}
/**
......@@ -111,6 +109,54 @@ public final class TtlExecutors {
return (T) ((ExecutorTtlWrapper) executor).unwrap();
}
/**
* Wrapper of {@link ThreadFactory}, disable inheritable.
*
* @param threadFactory input thread factory
* @see DisableInheritableThreadFactory
* @since 2.10.0
*/
@Nullable
public static ThreadFactory getDisableInheritableThreadFactory(@Nullable ThreadFactory threadFactory) {
if (threadFactory == null || isDisableInheritableThreadFactory(threadFactory)) return threadFactory;
return new DisableInheritableThreadFactoryWrapper(threadFactory);
}
/**
* Wrapper of {@link Executors#defaultThreadFactory()}, disable inheritable.
*
* @see #getDisableInheritableThreadFactory(ThreadFactory)
* @since 2.10.0
*/
@Nullable
public static ThreadFactory getDefaultDisableInheritableThreadFactory() {
return getDisableInheritableThreadFactory(Executors.defaultThreadFactory());
}
/**
* check the {@link ThreadFactory} is {@link DisableInheritableThreadFactory} or not.
*
* @see DisableInheritableThreadFactory
* @since 2.10.0
*/
public static boolean isDisableInheritableThreadFactory(@Nullable ThreadFactory threadFactory) {
return threadFactory instanceof DisableInheritableThreadFactory;
}
/**
* Unwrap {@link DisableInheritableThreadFactory} to the original/underneath one.
*
* @see DisableInheritableThreadFactory
* @since 2.10.0
*/
@Nullable
public static ThreadFactory unwrap(@Nullable ThreadFactory threadFactory) {
if (!isDisableInheritableThreadFactory(threadFactory)) return threadFactory;
return ((DisableInheritableThreadFactory) threadFactory).unwrap();
}
private TtlExecutors() {
}
}
package com.alibaba.ttl
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.ttl.threadpool.TtlExecutors
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Rule
import org.junit.Test
import java.util.concurrent.Callable
import java.util.concurrent.Executors
class InheritableTest {
@Rule
@JvmField
val rule = ConditionalIgnoreRule()
@Test
fun inheritable() {
val threadPool = Executors.newCachedThreadPool()
val ttl = TransmittableThreadLocal<String>()
ttl.set("hello")
val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!!
// get "hello" value is transmitted by InheritableThreadLocal function!
// NOTE: newCachedThreadPool create thread lazily
assertEquals("hello", threadPool.submit(callable).get())
threadPool.shutdown()
}
@Test
@ConditionalIgnore(condition = IsAgentRun::class)
fun disableInheritable() {
val threadPool = Executors.newCachedThreadPool(TtlExecutors.getDefaultDisableInheritableThreadFactory())
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())
threadPool.shutdown()
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册