網(wǎng)站首頁 編程語言 正文
一、多線程間的資源競爭
以下列task1()
,task2()
兩個(gè)函數(shù)為例,分別將對全局變量num加一重復(fù)一千萬次循環(huán)(數(shù)據(jù)大一些,太小的話執(zhí)行太快,達(dá)不到驗(yàn)證的效果)。
import threading import time num = 0 def task1(nums): ? ? global num ? ? for i in range(nums): ? ? ? ? num += 1 ? ? print("task1---num=%d" % num) def task2(nums): ? ? global num ? ? for i in range(nums): ? ? ? ? num += 1 ? ? print("task2---num=%d" % num) if __name__ == '__main__': ? ? nums = 10000000 ? ? t1 = threading.Thread(target=task1, args=(nums,)) ? ? t2 = threading.Thread(target=task2, args=(nums,)) ? ? t1.start() ? ? t2.start() ? ? # 因?yàn)橹骶€程不會等子線程執(zhí)行完就會執(zhí)行,所以這里延遲五秒,確保最后執(zhí)行。 ? ? time.sleep(5) ? ? print("main----num=%d" % num)
程序運(yùn)行結(jié)果:
如圖,輸出結(jié)果比較混亂,既沒有一千萬,最終結(jié)果也不是二千萬。因?yàn)槎嗑€程運(yùn)行時(shí)出現(xiàn)了資源競爭,即可以理解為,每個(gè)函數(shù)運(yùn)行的時(shí)間都不確定,且互相影響,
如從初始值0開始,假設(shè)t1的線程先執(zhí)行,執(zhí)行到+1后,此時(shí)的num=1還未存儲,然后即被叫停,t2開始執(zhí)行,去獲取num,獲取到的num等于初始值0,然后其執(zhí)行了+1并存儲,存儲后num=1,然后t2停止t1繼續(xù),再次存儲num=1。即加了兩次1,但是num還是只等于1。
因?yàn)閠1和t2誰來運(yùn)行的分配是完全隨機(jī)的,所以最后加了兩千萬次1后值是小于2000萬的。
解決此類問題,可以使用到互斥鎖 。
二、互斥鎖
- 某個(gè)線程要更改共享數(shù)據(jù)時(shí),先將其鎖定,此時(shí)資源的狀態(tài)為"鎖定",其他線程不能改變,只到該線程釋放資源,將資源的狀態(tài)變成"非鎖定",其他的線程才能再次鎖定該資源。
- 互斥鎖保證了每次只有一個(gè)線程進(jìn)行寫入操作,從而保證了多線程情況下數(shù)據(jù)的正確性。
1.互斥鎖示例
創(chuàng)建一把鎖:
mutex = threading.Lock()
mutex.acquire() # 上鎖 xxxx鎖定的內(nèi)容xxxxx mutex.release() # 解鎖
將互斥鎖加入到上邊的代碼中如下,則問題得到了解決。
import threading import time num = 0 def task1(nums): ? ? global num ? ? mutex.acquire() ? ? for i in range(nums): ? ? ? ? num += 1 ? ? mutex.release() ? ? print("task1---num=%d" % num) def task2(nums): ? ? global num ? ? mutex.acquire() ? ? for i in range(nums): ? ? ? ? num += 1 ? ? mutex.release() ? ? print("task2---num=%d" % num) if __name__ == '__main__': ? ? nums = 10000000 ? ? mutex = threading.Lock() ? ? t1 = threading.Thread(target=task1, args=(nums,)) ? ? t2 = threading.Thread(target=task2, args=(nums,)) ? ? t1.start() ? ? t2.start() ? ? # 因?yàn)橹骶€程不會等子線程執(zhí)行完就會執(zhí)行,所以這里延遲五秒,確保最后執(zhí)行。 ? ? time.sleep(5) ? ? print("main----num=%d" % num)
程序運(yùn)行結(jié)果:
2.可重入鎖與不可重入鎖
threading.Lock()
上的是不可重入鎖,即一次只能加一把鎖,不能加多把。
threading.Lock()
如果需要同時(shí)加多把所,則需加入不可重入鎖
創(chuàng)建一把可重入鎖:
mutex = threading.RLock() mutex.acquire() # 上鎖 mutex.acquire() # 再上鎖 xxxx鎖定的內(nèi)容xxxxx mutex.release() # 解鎖 mutex.release() # 再解鎖
其中上鎖和解鎖的次數(shù)必須保持一致。
三、死鎖
在線程間共享多個(gè)資源的時(shí)候,如果兩個(gè)線程分別占有一部分資源并且同時(shí)等待對方的資源,就會程序堵塞,造成死鎖。
- 死鎖一般用不到。
- 程序設(shè)計(jì)要盡量避免。
原文鏈接:https://skylarkprogramming.blog.csdn.net/article/details/122772134
相關(guān)推薦
- 2021-12-07 C#?微信支付回調(diào)驗(yàn)簽處理的實(shí)現(xiàn)_C#教程
- 2022-04-19 IDEA 快捷生成注釋 配置(完美不報(bào)警告)
- 2023-12-21 npm install 報(bào)錯(cuò)(npm ERR! errno: -4048, npm ERR! c
- 2022-12-15 Qt開發(fā)之使用socket實(shí)現(xiàn)遠(yuǎn)程控制_C 語言
- 2023-01-20 Python輸入整數(shù)進(jìn)行排序方式_python
- 2022-09-18 iOS開發(fā)探索多線程GCD常用函數(shù)_IOS
- 2022-11-03 React狀態(tài)管理器Rematch的使用詳解_React
- 2023-07-09 echart 設(shè)置柱狀圖y軸最大刻度
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支