Closed zongchangbo closed 5 years ago
目前发现的都是主线程到子线程的 值传递; 那从子线程到主线程的 却不能实现
你的需求场景是和要解决的问题是什么,可以先具体些 说明一下。 😄 @zongchangbo
TTL
缺省向子线程传递的是引用,即子线程改了,父线程是可见的 。
这即是 支持了 子线程向父线程 传递,注意线程安全。
TransmittableThreadLocal
提供的是 一个 典型场景下的规范化/模式化的解法,进而 简化 使用、实现和系统设计。关于『TTL
目标/功能/典型场景』参见文档:
JDK
的InheritableThreadLocal
类可以完成父线程到子线程的值传递。但对于使用线程池等会池化复用线程的组件的情况,线程由线程池创建好,并且线程是池化起来反复使用的;这时父子线程关系的ThreadLocal
值传递已经没有意义,应用需要的实际上是把 任务提交给线程池时的ThreadLocal
值传递到 任务执行时。
question
Tag:
https://github.com/alibaba/transmittable-thread-local/issues?utf8=%E2%9C%93&q=label%3Aquestion嗯 谢谢啊,TTL缺省向子线程传递的是引用, 而我之前用的是String 这种弱引用类型 ,所以失败了
COOL 解决了就好 ❤️
能说明一下你的需求场景/使用场景吗? @zongchangbo ❤️
方便 的话,请记到 Issue 【用户反馈收集】说一下您的使用场景、使用项目、公司,感谢! 中 :)
String
类型(Immutable
) 与 强弱引用之前用的是
String
这种弱引用类型 ,所以失败了
更准确地说, @zongchangbo
String
是实现成Immutable
的,即不可变的。所以父线程不可能看到子线程的变更。String
类型的变量,如果你没有做了专门的处理(如使用WeakHashMap
/ WeakReference
之类的),String
变量本身是强引用,而非弱引用。在 WeakReference
中,有关于弱引用的解释。
下面的这个demo是可以的:
public class CustomThreadLocal {
static TransmittableThreadLocal<String> threadLocal = new TransmittableThreadLocal<>();
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
CustomThreadLocal.threadLocal.set("test: " + new Random(10).nextInt());
new Service().call();
}
}).start();
}
}
class Service {
public void call() {
//System.out.println("Service:" + Thread.currentThread().getName());
System.out.println("Service:" + CustomThreadLocal.threadLocal.get());
new Dao().call();
}
}
class Dao {
public void call() {
System.out.println("==========================");
// System.out.println("Dao:" + Thread.currentThread().getName());
System.out.println("Dao:" + CustomThreadLocal.threadLocal.get());
}
}
但是我实际工作中的不行
@Slf4j
public class PrometheusMetricsInterceptor extends HandlerInterceptorAdapter {
static final Counter requestCounter = Counter.build()
.name("cuishoufen_http_requests_total").labelNames("path", "method", "code")
.help("Total requests.").register();
public static final TransmittableThreadLocal<String> localStatus = new TransmittableThreadLocal<String>();
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
String requestURI = request.getRequestURI();
String method = request.getMethod();
int status = response.getStatus();
requestCounter.labels(requestURI, method, localStatus.get() == null ? String.valueOf(status): localStatus.get()).inc();
localStatus.remove();
super.afterCompletion(request, response, handler, ex);
}
/////////////////////////////////////////////////////////
@HystrixCommand(
fallbackMethod = "getCuishouTag_fallback",
groupKey = "getCuishouTag",
commandKey = "getCuishouTag",
threadPoolKey = "getCuishouTag",
commandProperties = {
//设置调用者等待命令执行的超时限制,超过此时间,HystrixCommand被标记为TIMEOUT,并执行回退逻辑
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000"),
@HystrixProperty(name = "fallback.isolation.semaphore.maxConcurrentRequests", value = "200"),
//设置在一个滚动窗口中,打开断路器的最少请求数
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "4"),
//设置在回路被打开,拒绝请求到再次尝试请求并决定回路是否继续打开的时间
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "60000"),
//设置统计的滚动窗口的时间段大小。该属性是线程池保持指标时间长短
@HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "180000")
},
threadPoolProperties = {
@HystrixProperty(name = "coreSize", value = "30"),
@HystrixProperty(name = "maxQueueSize", value = "200"),
//设置队列拒绝的阈值——一个人为设置的拒绝访问的最大队列值,即使maxQueueSize还没有达到
@HystrixProperty(name = "queueSizeRejectionThreshold", value = "50"),
//设置统计的滚动窗口的时间段大小。该属性是线程池保持指标时间长短
@HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "180000")
}
)
@Override
public HashMap<String, String> getCuishouTag(String tel) {
HashMap<String,String> hm = new HashMap<String,String>();
try {
String param = buildParam(tel);
String response = getResponse(URL_2, param);
if (StringUtils.isNotBlank(response)) {
hm = parseResponse(response);
}
}catch (Exception e){
PrometheusMetricsInterceptor.localStatus.set("9999")
log.error("getCuishouTag process error, tel={}", tel, e);
return hm;
}
return hm;
}
}
然后我的解决方案就是把String 换成一个对象,请问为何会发生这样的事情?
@zongchangbo
因为 涉及 HandlerInterceptorAdapter
/HystrixCommand
,要具体分析这些涉及框架的 整体流程 与 代码实现。
这些 框架 我没有具体用过、不熟悉了解,所以 你要自己去分析一下了。 😄
目前发现的都是主线程到子线程的 值传递; 那从子线程到主线程的 却不能实现,这个有办法解决吗?
解决了吗? 我现在也遇到了同样的问题。我有一个需求是收集所有子线程的执行日志然后到父线程汇总 。
微信说吧,809116583
------------------ 原始邮件 ------------------ 发件人: "alibaba/transmittable-thread-local" @.>; 发送时间: 2022年7月19日(星期二) 晚上6:28 @.>; @.**@.>; 主题: Re: [alibaba/transmittable-thread-local] 如何子线程向父线程传递值? (#125)
目前发现的都是主线程到子线程的 值传递; 那从子线程到主线程的 却不能实现,这个有办法解决吗?
解决了吗? 我现在也遇到了同样的问题。我有一个需求是收集所有子线程的执行日志然后到父线程汇总 。
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.Message ID: @.***>
目前发现的都是主线程到子线程的 值传递; 那从子线程到主线程的 却不能实现,这个有办法解决吗?