为何添加thread.join()后Python多线程代码表现更安全?
问题描述
以下是一段Python多线程代码:
import threading # Shared variable shared_variable = 0 NUM_THREADS = 999 NUM_INCREMENT = 1_000_000 # Function to increment the shared variable def increment(): global shared_variable for _ in range(NUM_INCREMENT): shared_variable += 1 # Creating multiple threads to increment the shared variable concurrently threads = [] for _ in range(NUM_THREADS): thread = threading.Thread(target=increment) threads.append(thread) for thread in threads: thread.start() for thread in threads: thread.join() # Display the value of the shared variable after concurrent increments print( f"The value of the shared variable is: {shared_variable}, expected : {NUM_THREADS * NUM_INCREMENT}" )
当保留thread.join()代码块时,程序输出的共享变量值始终符合预期(即999 * 1000000);但注释掉该段代码后:
# for thread in threads: # thread.join()
会出现递增操作失效的情况(结果小于预期)。请问为何添加thread.join()后该多线程代码表现得更安全?
原因解析
核心原因和主线程的执行时机直接相关:
- 不调用
join()时,主线程启动所有子线程后,会立刻继续执行后续代码,直接跑到print语句输出结果,甚至可能在子线程还没完成全部递增操作前,主线程就已经结束了。Python中主线程结束时会强制终止所有仍在运行的子线程,这就导致大量递增操作根本没机会执行,最终结果自然远小于预期值。 - 调用
join()的作用就是让主线程进入阻塞状态,必须等所有子线程全部执行完毕后,才会继续执行后续的打印代码。这样所有子线程的递增操作都能完整执行,你看到的结果才会符合预期。
额外说明:这里要注意,shared_variable += 1本质上是线程不安全的操作——它拆分为读取当前值、加1、写入新值三个独立步骤,多线程并发时会出现竞态条件,导致值被覆盖。你这次测试中加join()后结果符合预期只是巧合,若线程调度时机特殊,即使加了join(),理论上还是可能出现结果不符合预期的情况。正确保证线程安全的做法是给共享变量的操作加锁(比如threading.Lock()),确保递增操作是原子性的。
内容的提问来源于stack exchange,提问作者Anis Smail
相关产品推荐
相关产品推荐

