網站首頁 編程語言 正文
一、多線程共享全局變量
代碼實現的功能:
創建work01與worker02函數,對全局變量進行加一操作創建main函數,生成兩個線程,同時調用兩個函數
代碼如下:
import threading result = 0 # 定義全局變量result def work1(num): global result for i in range(num): result += 1 print('------from work1-------', result) def work2(num): global result for i in range(num): result += 1 print('------from work2-------', result) def main(): print('--------begin--------', result) # 創建兩個線程 t1 = threading.Thread(target=work1, args=(1000,)) t2 = threading.Thread(target=work1, args=(1000,)) t1.start() t2.start() if __name__ == '__main__': main()
運行結果:
--------begin---------- 0 ------from work1------- 1000 ------from work1------- 2000
兩個線程之間共享了全局變量result,但是當我們把range的數值調大一些,
t1 = threading.Thread(target=work1, args=(1000000,)) t2 = threading.Thread(target=work1, args=(1000000,))
我們再來看一下結果,這是為什么呢,我們往下看一下結果:
--------begin---------- 0 ------from work1------- 1358452 ------from work1------- 1696352
總結:
在一個進程內的所有線程共享全局變量,很方便在多個線程間共享數據
缺點就是,線程是對全局變量隨意遂改可能造成多線程之間對全局變量的混亂(即線程非安全)
二、給線程加一把鎖鎖
假如當前 g_num 值是100,當線程1執行第一步時,cpu通過計算獲得結果101,并準備把計算的結果101賦值給g_num,然后再傳值的過程中,線程2突然開始執行了并且執行了第一步,此時g_num的值仍未100,101還在傳遞的過程中,還沒成功賦值,線程2獲得計算結果101,并準備傳遞給g_num,經過一來一去這么一折騰,分明做了兩次加 1 操作,g_num結果卻是101,誤差就由此產生,往往循環次數越多,產生的誤差就越大,此時我們可以加一把鎖。
acquire() — 鎖定資源,此時資源是鎖定狀態,其他線程無法修改鎖定的資源,直到等待鎖定的資源釋放之后才能操作;
release() — 釋放資源,也稱為解鎖操作,對鎖定的資源解鎖,解鎖之后其他線程可以對資源正常操作;
以上面的代碼為列子:想得到正確的結果,可以直接利用互斥鎖在全局變量 加1 之前 鎖定資源,然后在計算完成之后釋放資源,這樣就是一個完整的計算過程,至于應該是哪個線程先執行,無所謂,先到先得,憑本事說話….演示代碼如下:
# 開發時間:2022-01-27 12:59 import threading result = 0 # 定義全局變量result mutex = threading.Lock() def work1(num): global result mutex.acquire() for i in range(num): result += 1 print('------from work1-------', result) mutex.release() def work2(num): global result mutex.acquire() for i in range(num): result += 1 print('------from work2-------', result) mutex.release() def main(): print('--------begin----------', result) # 創建兩個線程 t1 = threading.Thread(target=work1, args=(100000000,)) t2 = threading.Thread(target=work1, args=(100000000,)) t1.start() t2.start() if __name__ == '__main__': main()
我們來看一下結果:
--------begin---------- 0 ------from work1------- 100000000 ------from work1------- 200000000
三、死鎖問題
1.單個互斥鎖的死鎖:
acquire()/release() 是成對出現的,互斥鎖對資源鎖定之后就一定要解鎖,否則資源會一直處于鎖定狀態,其他線程無法修改;就好比上面的代碼,任何一個線程沒有釋放資源release(),程序就會一直處于阻塞狀態(在等待資源被釋放),不信你可以試一試~
2.多個互斥鎖的死鎖:
在同時操作多個互斥鎖的時候一定要格外小心,因為一不小心就容易進入死循環,假如有這樣一個場景:boss讓程序員一實現功能一的開發,讓程序員二實現功能二的開發,功能開發完成之后一起整合代碼!
# 導入線程threading模塊 import threading # 導入線程time模塊 import time # 創建互斥鎖 mutex_one = threading.Lock() mutex_two = threading.Lock() def programmer_thread1(): mutex_one.acquire() print("我是程序員1,module1開發正式開始,程序一加鎖,程序二加鎖") time.sleep(2) # 此時會堵塞,因為這個mutex_two已經被線程programmer_thread2搶先上鎖了,等待解鎖 mutex_two.acquire() print("等待程序員2通知我合并代碼") mutex_two.release() print('程序員2開發完了,程序員1釋放第二把鎖') mutex_one.release() print('程序員1開發完了,程序員1釋放第一把鎖') def programmer_thread2(): mutex_two.acquire() print("我是程序員2,module2開發正式開始,程序二加鎖,程序一加鎖") time.sleep(2) # 此時會堵塞,因為這個mutex_one已經被線程programmer_thread1搶先上鎖了,等待解鎖 #mutex_two.release() mutex_one.acquire() print("等待程序員1通知我合并代碼") mutex_one.release() print('程序員2釋放第一把鎖') # mutex_two.release() print('程序員2釋放第二把鎖') def main(): t1 = threading.Thread(target=programmer_thread1) t2 = threading.Thread(target=programmer_thread2) # 啟動線程 t1.start() t2.start() # 阻塞函數,等待線程結束 t1.join() t2.join() # 整合代碼結束 print("整合代碼結束 ") if __name__ == "__main__": main()
分析下上面代碼:程序員1在等程序員2通知,程序員2在等程序員1通知,兩個線程都陷入阻塞中,因為兩個線程都在等待對方解鎖,這就是死鎖!所以在開發中對于死鎖的問題還是需要多多注意!
總結
原文鏈接:https://blog.csdn.net/weixin_43143310/article/details/122716201
相關推薦
- 2023-01-02 Kotlin?RadioGroup與ViewPager實現底層分頁按鈕方法_Android
- 2022-04-20 Python設計模式行為型責任鏈模式_python
- 2022-08-21 Python?正則?re.compile?真的必需嗎_python
- 2023-04-26 C++變量初始化形式及其默認初始值問題_C 語言
- 2022-07-15 在SQL?Server中使用子查詢更新語句_MsSql
- 2022-12-08 Anaconda中pkgs文件夾及如何清空PKGS_相關技巧
- 2023-07-05 cnpm安裝appium出現cannot find module xxx
- 2022-05-06 golang-操作sqlite3增刪改查
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支