线程——子线程、无参数

多线程程序示例
本文展示了一个使用pthread库创建两个并行线程的C语言程序实例。其中一个线程会在循环中打印消息直到特定条件触发退出,另一个线程则简单地执行几次打印后退出。
 

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>

void thread1(void)
{
 int i=0;
 for(i=0;i<6;i++)
 {
  printf("This is a pthread1.\n");
  if(i==2)
   pthread_exit(0);
  sleep(1);
 }
}

void thread2(void)
{
 int i;
 for(i=0;i<3;i++)
  printf("This is a pthread2.\n");
 pthread_exit(0);
}

int main(void)
{
 pthread_t id1,id2;
 //int i,ret;
 int ret;
 ret=pthread_create(&id1,NULL,(void *) thread1,NULL);//(void *) thread1//函数传递事,传过去的就地址
 if(ret!=0)
 {
  printf ("Create pthread error!\n");
  exit (1);
 }
 ret=pthread_create(&id2,NULL,(void *) thread2,NULL);
 if(ret!=0)
 {
  printf ("Create pthread error!\n");
  exit (1);
 }
 pthread_join(id1,NULL);
 pthread_join(id2,NULL);
 exit (0);
}

 

<think> 嗯,用户需要了解在异步子线程中获取主线程上下文的方法。用户提供了多个关于Java异步线程获取主线程request属性的引用资料,这些引用描述了常见问题点和解决方案。用户的问题比较聚焦在技术实现层面,特别是主线程结束后子线程访问其上下文的情况。 用户可能正在开发Web应用,遇到了异步处理时上下文丢失的问题。从引用中可以看出,用户关注的核心矛盾在于主线程生命周期结束后子线程无法访问其request对象。引用[2]和[4]明确提到共享的前提是主线程必须等待子线程完成,否则request会被销毁。 需要重点考虑的技术点有三个:一是线程封闭模式如何实现上下文递,二是异步框架的上下文播机制,三是防御性编程策略。引用[4]提到的RequestContextHolder和inheritableThreadLocals机制很关键,这是Spring框架处理该问题的核心方案。但要注意引用[2]强调的生命周期管理问题——如果主线程等待,即使使用InheritableThreadLocal也会失效。 对于解决方案,应该分层说明。首先是基础方案线程局部变量递,用代码示例展示ThreadLocal和InheritableThreadLocal的区别;然后是框架级方案,突出Spring的RequestContextHolder实现原理;最后是补充方案如上下文包装对象和线程同步控制。特别要强调引用[4]中DispatcherServlet的processRequest方法如何设置requestAttributesHolder这个实现细节。 安全方面必须提醒内存泄漏风险,ThreadLocal使用后必须remove这点要重点标注。生命周期管理建议参考引用[2]的主从线程同步方案。性能方面注意InheritableThreadLocal的复制开销,在频繁创建线程的场景可能成为瓶颈。 用户可能需要更清晰的代码示例,特别是RequestContextHolder的使用范例。但根据对话历史,系统要求避免输出完整代码,所以用伪代码说明关键步骤即可。另外可以提示用户,如果使用CompletableFuture等高级异步工具,上下文播会更简便。 相关问题设计要覆盖延伸场景:比如用户可能后续会问分布式链路追踪中的上下文播,或者非Web环境如定时任务的上下文继承问题。技术深度上可以引导到Java的ScopedValue新特性,这是未来替代InheritableThreadLocal的方案。 </think> 在异步子线程中获取主线程上下文的核心方法是利用**线程封闭(Thread Confinement)技术**和**上下文递机制**。以下是具体实现方案及注意事项,综合引用内容分析: --- ### **一、核心方法** #### 1. **使用`InheritableThreadLocal`(推荐)** Java 提供`InheritableThreadLocal`,子线程可自动继承主线程的上下文: ```java private static final InheritableThreadLocal<HttpServletRequest> requestHolder = new InheritableThreadLocal<>(); // 主线程存储Request @GetMapping("/async") public String asyncHandler(HttpServletRequest request) { requestHolder.set(request); // 存储到ThreadLocal executor.submit(() -> { try { Thread.sleep(1000); HttpServletRequest subReq = requestHolder.get(); // 子线程获取 System.out.println("属性值:" + subReq.getAttribute("key1")); } finally { requestHolder.remove(); // 防止内存泄漏 } }); return "OK"; } ``` **原理**: 子线程通过`InheritableThreadLocal`拷贝主线程的上下文引用[^4]。 --- #### 2. **Spring的`RequestContextHolder`(需线程池支持)** Spring Boot 中通过`RequestContextHolder`递Request: ```java // 主线程 @GetMapping("/asyncTest") public String asyncTest() { RequestAttributes attributes = RequestContextHolder.getRequestAttributes(); executor.submit(() -> { RequestContextHolder.setRequestAttributes(attributes); // 绑定到子线程 try { HttpServletRequest request = ((ServletRequestAttributes) attributes).getRequest(); System.out.println("值:" + request.getAttribute("key1")); } finally { RequestContextHolder.resetRequestAttributes(); // 清理 } }); return "OK"; } ``` **关键点**: - 需确保线程池支持上下文递(如使用`TaskDecorator`包装任务)[^3][^4]; - 主线程需等待子线程完成,否则Request对象可能被销毁[^2][^4]。 --- #### 3. **显式递上下文对象** 将所需参数封装为独立对象递,避免直接操作Request: ```java executor.submit(() -> doExe( request.getAttribute("key1"), // 提前提取值 request.getSession().getId() // 递必要数据 )); ``` **优势**: 解耦线程依赖,避免生命周期问题[^2][^5]。 --- ### **二、注意事项** 1. **生命周期管理** - 若主线程提前结束,Request对象会被销毁,子线程访问将失败[^2][^4]; - **解决方案**:使用`CompletableFuture`等机制等待子线程完成(如`future.join()`)[^2]。 2. **内存泄漏风险** - `ThreadLocal`使用后必须调用`remove()`清理,否则导致内存泄漏[^4]。 3. **异步框架集成** - 推荐使用Spring的`@Async` + `AsyncConfigurer`自定义线程池,注入`TaskDecorator`递上下文: ```java public class ContextAwareTaskDecorator implements TaskDecorator { @Override public Runnable decorate(Runnable runnable) { RequestAttributes context = RequestContextHolder.getRequestAttributes(); return () -> { try { RequestContextHolder.setRequestAttributes(context); runnable.run(); } finally { RequestContextHolder.resetRequestAttributes(); } }; } } ``` --- ### **三、适用场景总结** | **方法** | 适用场景 | 风险 | |-------------------------|-----------------------------------|--------------------| | `InheritableThreadLocal` | 简单异步任务 | 需手动清理上下文 | | `RequestContextHolder` | Spring项目(配置线程池支持) | 主线程可提前结束 | | 显式参数递 | 高并发或分布式场景 | 需重构业务逻辑 | > **关键结论**:若主线程等待子线程,任何共享Request的方案均会失效[^2][^4]。此时应优先选择**显式参数递**或**消息队列**解耦。 --- ### **相关问题** 1. 如何避免主线程结束后子线程无法访问Request的问题? 2. `InheritableThreadLocal`在线程池复用场景下为何失效?如何解决? 3. Spring Boot中如何配置支持上下文递的异步线程池? 4. 分布式系统中异步任务如何递上下文(如TraceID)? 5. 使用`CompletableFuture`时如何确保主线程等待子线程完成? [^1]: Java异步子线程读取主线程参数的若干好玩场景 [^2]: 多线程异步操作子线程获取到主线程request信息问题解决及源码解析 [^3]: 异步子线程共享主线程request [^4]: 异步子线程如何获取主线程的request中的属性 [^5]: 子线程获取主线程的Request对象问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值