Join() 方法 & ThreadLocal 类的使用

本文介绍了Java中线程控制方法join与sleep的区别,并详细解释了ThreadLocal与InheritableThreadLocal类的使用方法,帮助读者理解如何有效地管理和控制线程间的同步与局部变量的传递。

方法 Join 的使用

join() & join(long)方法

join()作用:在 A 线程中调用了 B 线程的 join() 方法时,表示只有当 B 线程执行完毕时, A 线程才能继续执行

join(long)作用:如果 A 线程中调用 B 线程的 join(10),则表示 A 线程会等待 B 线程执行10毫秒,10毫秒过后,A、B线程并行执行

注意:join(0)等价于join()

何时调用:join 方法必须在线程 start 方法调用之后调用才有意义。

join 与 synchronized 的区别:

join 在内部使用 wait() 方法进行等待,而 synchronized 使用的是”对象监视器“原理作为同步

join(long) 与 sleep(long) 的区别:

join(long) 会释放锁,而 sleep(long) 不释放锁

例如:A 线程中调用了 B 线程的 join 方法,则相当于 A 线程调用了 B 线程的 wait 方法,调用之后 A 线程就会进入阻塞状态(释放 A 线程的锁),当 B 线程执行完(或者到达等待时间),B 线程会自动调用自身的 notifyAll 方法唤醒 A 线程,从而达到同步的目的。

类 ThreadLocal & InheritableThreadLocal 的使用

ThreadLocal 类

主要解决的是:每个线程绑定自己的变量(存储每个线程的私有数据)。

get():取数据

set():存数据

InheritableThreadLocal

主要解决的是:可以在子线程中取得父线程继承下来的值。

注意:如果子线程在取得值的同时,主线程将 InheritableThreadLocal 中的值进行更改,那么子线程取得的值还是旧值

<think>我们正在讨论C++中的`thread_local`关键字。根据引用内容,`thread_local`是C++11引入的存储期说明符,用于声明线程本地存储(TLS)变量。每个线程都有该变量的独立副本,线程之间互不干扰。 下面我将详细解释`thread_local`的使用方法,并给出示例。 ### 1. `thread_local`的基本概念 `thread_local`声明的变量具有线程存储期。这意味着: - 每个线程拥有该变量的独立实例 - 变量的生命周期与线程绑定(对于非静态局部变量,当线程退出销毁) - 不同线程对同一`thread_local`变量的修改互不影响 ### 2. 使用语法 #### 2.1 全局变量 ```cpp thread_local int global_tls_var = 0; // 全局线程局部变量 ``` #### 2.2 静态成员变量 ```cpp class MyClass { public: thread_local static int static_tls_var; // 声明 }; // 定义(注意:必须在外定义) thread_local int MyClass::static_tls_var = 0; ``` #### 2.3 局部变量(函数内) ```cpp void func() { thread_local int local_tls_var = 0; // 每个线程第一次进入初始化 ++local_tls_var; } ``` ### 3. 示例代码分析 #### 示例1:全局`thread_local`变量(来自引用[2]稍作修改) ```cpp #include <iostream> #include <thread> thread_local int tls_var = 0; // 全局线程局部变量 void increment() { ++tls_var; // 每个线程修改自己的副本 std::cout << "Thread " << std::this_thread::get_id() << ": tls_var = " << tls_var << std::endl; } int main() { std::thread t1(increment); // 线程1 std::thread t2(increment); // 线程2 t1.join(); t2.join(); // 主线程访问自己的副本 std::cout << "Main thread: tls_var = " << tls_var << std::endl; return 0; } ``` **输出分析**(可能的一种输出): ``` Thread 140737295853312: tls_var = 1 Thread 140737287460608: tls_var = 1 Main thread: tls_var = 0 ``` **解释**: - 每个线程(包括主线程)都有自己的`tls_var`副本 - 线程1和线程2分别将各自的副本从0增加到1 - 主线程的副本保持初始值0 #### 示例2:局部`thread_local`变量(来自引用[3]稍作修改) ```cpp #include <iostream> #include <thread> #include <string> class A { public: void test(const std::string &name) { thread_local int count = 0; // 每个线程第一次调用test初始化 ++count; std::cout << name << ": count = " << count << std::endl; } }; void func(const std::string &name) { A a1; a1.test(name); // 第一次调用:count=1 a1.test(name); // 第二次调用:count=2 A a2; a2.test(name); // 同一个线程继续调用:count=3 a2.test(name); // count=4 } int main() { std::thread t1(func, "t1"); t1.join(); std::thread t2(func, "t2"); t2.join(); return 0; } ``` **输出**: ``` t1: count = 1 t1: count = 2 t1: count = 3 t1: count = 4 t2: count = 1 t2: count = 2 t2: count = 3 t2: count = 4 ``` **解释**: - 局部`thread_local`变量`count`在函数`test`内声明 - 每个线程首次进入`test`函数初始化`count`为0 - 同一线程后续调用`test`,`count`保持上次调用的值(不会重新初始化) - 不同线程的`count`相互独立 ### 4. 关键注意事项 1. **初始化机**:`thread_local`变量在每个线程中第一次使用前初始化(懒初始化) 2. **析构机**:线程退出,按照初始化顺序的逆序销毁 3. **与`static`结合**: - `thread_local static`用于的静态成员变量(必须在外定义) - 函数内的`thread_local`变量隐含`static`存储期(即只初始化一次,但每个线程独立) 4. **性能考虑**:访问`thread_local`变量通常比普通全局变量慢,但比互斥锁快 ### 5. 适用场景 - 线程特定的计数器 - 线程特定的缓存 - 避免传递上下文参数(如日志记录器) - 替代不可重入函数中的静态变量 §§相关问题§§ 1. `thread_local`变量与静态局部变量有何本质区别? 2. 如何实现跨平台的线程局部存储? 3. `thread_local`在动态链接库中使用有哪些注意事项? 4. 多个线程初始化`thread_local`变量是否安全? 5. `thread_local`变量能否用于线程池场景?</think>### C++ `thread_local` 关键字详解 `thread_local` 是 C++11 引入的存储期说明符,用于声明**线程局部存储(Thread Local Storage, TLS)** 变量。每个线程都有该变量的独立副本,线程之间互不干扰,特别适合保存线程特定状态(如计数器、缓存等)。 --- #### 一、核心特性 1. **线程独立性** 每个线程拥有变量的独立副本,修改互不影响。 2. **生命周期** - 全局变量:线程启动构造,线程结束销毁 - 局部变量:首次访问构造,线程结束销毁 3. **初始化** 默认零初始化,支持动态初始化(如构造函数)。 --- #### 二、使用场景与语法 | **型** | **语法示例** | **作用域** | |-------------------|---------------------------------------|------------------| | 全局变量 | `thread_local int count = 0;` | 整个程序 | | 静态成员 | `class A { thread_local static int x; }` | 作用域 | | 局部变量 | `void func() { thread_local int y; }` | 函数作用域 | --- #### 三、关键示例解析 ##### 示例 1:全局变量(独立计数器) ```cpp #include <iostream> #include <thread> thread_local int counter = 0; // 每个线程独立副本[^2] void increment() { ++counter; // 修改仅影响当前线程 std::cout << "Thread " << std::this_thread::get_id() << ": counter=" << counter << "\n"; } int main() { std::thread t1(increment); // 线程1:counter=1 std::thread t2(increment); // 线程2:counter=1(独立) t1.join(); t2.join(); } ``` **输出可能**: ``` Thread 140245291317120: counter=1 Thread 140245282924416: counter=1 ``` ##### 示例 2:局部变量(函数内 TLS) ```cpp class Logger { public: void log(const std::string& msg) { thread_local int call_count = 0; // 每个线程独立计数[^3] std::cout << "[" << ++call_count << "] " << msg << "\n"; } }; void task(const std::string& name) { Logger logger; logger.log(name + ": start"); logger.log(name + ": end"); } int main() { std::thread t1(task, "Thread1"); std::thread t2(task, "Thread2"); t1.join(); t2.join(); } ``` **输出**: ``` [1] Thread1: start // 线程1的call_count [2] Thread1: end [1] Thread2: start // 线程2的call_count独立 [2] Thread2: end ``` ##### 示例 3:静态成员变量 ```cpp class MyClass { public: thread_local static int id; // 声明 }; thread_local int MyClass::id = 0; // 外定义[^2] void worker() { MyClass::id = std::hash<std::thread::id>{}(std::this_thread::get_id()); std::cout << "Thread ID Hash: " << MyClass::id << "\n"; } int main() { std::thread t1(worker); std::thread t2(worker); t1.join(); t2.join(); } ``` --- #### 四、关键注意事项 1. **构造/析构顺序** 线程退出按初始化**逆序**析构 `thread_local` 对象。 2. **动态库兼容性** 在动态库中使用需确保编译器支持 TLS(Windows/Linux 均支持)。 3. **性能开销** 访问速度比普通全局变量慢(需查线程局部存储表),但比锁快。 4. **初始化线程安全** C++11 保证初始化仅发生一次,线程安全。 --- #### 五、典型应用场景 1. 线程特定缓存(如内存池) 2. 线程安全计数器 3. 避免传递上下文参数(如日志记录器) 4. 替换不可重入函数中的静态变量
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值