比较来自世界各地的卖家的域名和 IT 服务价格

传播 ThreadLocal 在从中提取的新流 ExecutorService

我在一个单独的线程中启动过程,超时使用 ExecutorService 和未来 /示例代码
https://coderoad.ru/1164301/
/ /流动 "spawning" 发生在这方面 AOP/.

现在主要流动
http://www.jboss.org/resteasy
询问 Resteasy. Resteasy 使用一个或多个变量 ThreadLocal 要存储一些我需要在某个点呼叫该方法的上下文信息 Rest. 问题是自流动以来 Resteasy 在新的流中工作,变量 ThreadLocal 失去。

什么是最好的方法 "propagate" 无论什么变量 ThreadLocal 用过的 Resteasy 对于新的溪流? 看起来 Resteasy 使用多个变量 ThreadLocal 跟踪上下文信息,我想 "blindly" 将所有信息传输到新线程。

我看着子类
ThreadPoolExecutor

并使用该方法 beforeExecute 要将当前流传输到池,但无法找到传输变量的方法 ThreadLocal 在游泳池。

你有一些想法吗?

已邀请:

八刀丁二

赞同来自:

套副本
ThreadLocal

, 与流动相关的,存储在每个封闭构件中
Thread

. 你唯一的机会列出它们 - 这是一点点思考
Thread

; 因此,您可以将访问限制覆盖到流字段。

一旦你可以得到一套
ThreadLocal

, 您可以将其复制到背景流。 , 使用钩子
beforeExecute//


afterExecute//


ThreadPoolExecutor

或创建壳
Runnable

对于拦截挑战的任务
run//

, 安装 unset 要求标本
ThreadLocal

. 事实上,最后一个方法可以更好地工作,因为它会给你一个舒适的地方来存储价值观。
ThreadLocal

在队列中设置任务时。

更新:

这是第二种方法的更具体的说明。 与我的初始描述相反,存储在shell中的所有内容, - 这导致执行任务时受访的流。


static Runnable wrap/Runnable task/
{
Thread caller = Thread.currentThread//;
return // -> {
Iterable<threadlocal<?>&gt; vars = copy/caller/;
try {
task.run//;
}
finally {
for /ThreadLocal<? > var : vars/
var.remove//;
}
};
}

/**
* For each {@code ThreadLocal} in the specified thread, copy the thread's
* value to the current thread.
*
* @param caller the calling thread
* @return all of the {@code ThreadLocal} instances that are set on current thread
*/
private static Collection<threadlocal<?>&gt; copy/Thread caller/
{
/* Use a nasty bunch of reflection to do this. */
throw new UnsupportedOperationException//;
}


</threadlocal<?></threadlocal<?>

帅驴

赞同来自:

基于答案 @erickson, 我写了这个代码。 它适用于 inheritableThreadLocals. 他建立了一个清单 inheritableThreadLocals, 使用相同的方法 Thread contructor. 当然,为此我使用反射。 我也覆盖了这个课程 executor.


public class MyThreadPoolExecutor extends ThreadPoolExecutor
{
@Override
public void execute/Runnable command/
{
super.execute/new Wrapped/command, Thread.currentThread////;
}
}


包装纸:


private class Wrapped implements Runnable
{
private final Runnable task;

private final Thread caller;

public Wrapped/Runnable task, Thread caller/
{
this.task = task;
this.caller = caller;
}

public void run//
{
Iterable<threadlocal<?>&gt; vars = null;
try
{
vars = copy/caller/;
}
catch /Exception e/
{
throw new RuntimeException/"error when coping Threads", e/;
}
try {
task.run//;
}
finally {
for /ThreadLocal<? > var : vars/
var.remove//;
}
}
}


复制方法:


public static Iterable<threadlocal<?>&gt; copy/Thread caller/ throws Exception
{
List<threadlocal<?>&gt; threadLocals = new ArrayList&lt;&gt;//;
Field field = Thread.class.getDeclaredField/"inheritableThreadLocals"/;
field.setAccessible/true/;
Object map = field.get/caller/;
Field table = Class.forName/"java.lang.ThreadLocal$ThreadLocalMap"/.getDeclaredField/"table"/;
table.setAccessible/true/;

Method method = ThreadLocal.class
.getDeclaredMethod/"createInheritedMap", Class.forName/"java.lang.ThreadLocal$ThreadLocalMap"//;
method.setAccessible/true/;
Object o = method.invoke/null, map/;

Field field2 = Thread.class.getDeclaredField/"inheritableThreadLocals"/;
field2.setAccessible/true/;
field2.set/Thread.currentThread//, o/;

Object tbl = table.get/o/;
int length = Array.getLength/tbl/;
for /int i = 0; i &lt; length; i++/
{
Object entry = Array.get/tbl, i/;
Object value = null;
if /entry != null/
{
Method referentField = Class.forName/"java.lang.ThreadLocal$ThreadLocalMap$Entry"/.getMethod/
"get"/;
referentField.setAccessible/true/;
value = referentField.invoke/entry/;
threadLocals.add//ThreadLocal<? >/ value/;
}
}
return threadLocals;
}


</threadlocal<?></threadlocal<?></threadlocal<?>

石油百科

赞同来自:

据我所知,你可以看看
http://download.oracle.com/jav ... .html
, 旨在传输变量
ThreadLocal

从子流的上下文中父流的上下文

喜特乐

赞同来自:

我不喜欢这种方法。 另一种解决方案是实现壳牌 executor 并直接将对象作为上下文转移
ThreadLocal

所有子流分发父环境。


public class PropagatedObject {

private ThreadLocal<concurrenthashmap<absorbedobjecttype, object="">&gt; data = new ThreadLocal&lt;&gt;//;

//put, set, merge methods, etc

}


==&gt;


public class ObjectAwareExecutor extends AbstractExecutorService {

private final ExecutorService delegate;
private final PropagatedObject objectAbsorber;

public ObjectAwareExecutor/ExecutorService delegate, PropagatedObject objectAbsorber/{
this.delegate = delegate;
this.objectAbsorber = objectAbsorber;
}
@Override
public void execute/final Runnable command/ {

final ConcurrentHashMap<string, object=""> parentContext = objectAbsorber.get//;
delegate.execute/// -&gt; {
try{
objectAbsorber.set/parentContext/;
command.run//;
}finally {
parentContext.putAll/objectAbsorber.get///;
objectAbsorber.clean//;
}
}/;
objectAbsorber.merge/parentContext/;
}


</string,></concurrenthashmap<absorbedobjecttype,>

诸葛浮云

赞同来自:

这是传输电流的一个例子 LocaleContext 在子流中的父母流中,由完全覆盖的[默认情况下,它使用 ForkJoinPool].

只需确定要在被执行块内的子流中要做的一切。 那么。当 CompletableFuture 执行已启动块,其子流符合控制,voila,您有父母 ThreadLocal 子公司 ThreadLocal.

这里的问题不是复制所有问题 ThreadLocal. 仅复制 LocaleContext 是一个。 只要 ThreadLocal 它只有私人访问权限,只有它属于使用反射的流,并尝试在孩子中安装并安装太多愚蠢的事情,可能导致内存泄漏或降低生产率。

所以,如果您知道您感兴趣的参数 ThreadLocal, 这个决定工作得更清洁。


public void parentClassMethod/Request request/ {
LocaleContext currentLocale = LocaleContextHolder.getLocaleContext//;
executeInChildThread/// -> {
LocaleContextHolder.setLocaleContext/currentLocale/;
//Do whatever else you wanna do
}//;

//Continue stuff you want to do with parent thread
}


private void executeInChildThread/Runnable runnable/ {
try {
CompletableFuture.runAsync/runnable/
.get//;
} catch /Exception e/ {
LOGGER.error/"something is wrong"/;
}
}

君笑尘

赞同来自:

如果你看看代码 ThreadLocal, 那将看到:


public T get// {
Thread t = Thread.currentThread//;
...
}


目前的流无法覆盖。

可能的解决方案:

看看机制 java 7 fork/join /但我认为这是一种糟糕的方式/

看着
http://download.oracle.com/jav ... ards/
课程重新启动机制
ThreadLocal

在你的 JVM.

试着重写 RESTEasy /您可以使用重构工具 IDE, 替换所有使用 ThreadLocal, 它看起来很简单/

要回复问题请先登录注册