摘要:并發(fā)同步控制遇到并發(fā)時,我們避免不了要談并發(fā)控制。它會阻塞其它的線程執(zhí)行,如果當前線程一直持有的監(jiān)控鎖,就會把其它線程一直阻塞下去。如果此時線程和線程同時進入方法,用一段語言描述方法的執(zhí)行過程,可能是這樣子。
并發(fā)同步控制
遇到并發(fā)時,我們避免不了要談并發(fā)控制。在Java語言中,我們談并發(fā)時,要談到Object的監(jiān)控鎖。在MySQL的數(shù)據(jù)庫并發(fā)中,我們也要談到mysql的鎖機制。
這樣說,說到并發(fā)就避免不了鎖的概念,不管是在像Java這種語言還是MySQL這樣的數(shù)據(jù)庫產(chǎn)品,我們都是利用鎖進行并發(fā)控制,或者說是同步控制。
控制并發(fā)的兩種方式(樂觀鎖與悲觀鎖)我們一般都可以想到或者可以理解的簡單解決辦法就是,把并發(fā)轉(zhuǎn)成串行的執(zhí)行的辦法。在簡單的串行情況,不存在并發(fā)的問題,那我們自然也就不存在鎖的概念了。拿Java的線程同步來說,如果有一個變量 a = 1 此時如果有兩個線程修改同執(zhí)行下面操作
a = 2; a = 0;
那么我們一般可以通過下面形式進行解決
public final static Object writeMonitor = new Object() void setA(int a){ synchronize(writeMonitor){ this.a = a; } }
此時,兩個線程只有一個線程執(zhí)行完上面步驟后,才會允許下一個線程執(zhí)行。這就是把并發(fā)轉(zhuǎn)為串行的列子。它會阻塞其它的線程執(zhí)行,如果當前線程一直持有的writeMonitor監(jiān)控鎖,就會把其它線程一直阻塞下去。這種并發(fā)控制的鎖,我們一般稱為悲觀鎖。對應的MySQL的Innodb引擎來說,我們利用Innodb的行鎖就是悲觀鎖的一種方式,但實際生產(chǎn)環(huán)境中,我們會很少使用它的行鎖,即很少用悲觀鎖去解決數(shù)據(jù)庫的并發(fā)問題。
在悲觀鎖的這種控制情況下,我們可以理解為:問題總是很糟糕,只能以最粗暴也最簡單的解決方式,就是所有的并發(fā)都給我一個一個執(zhí)行。這種方式在某些場景確實很有用,比如redis的并發(fā)控制就是這么實現(xiàn)。
相對于悲觀鎖這種方式,還會有另外一種解決并發(fā)的辦法。還以Java語言中的一些設計來談。在Java的并發(fā)工具包JUC下有個atomic包,比如AtomicIntegr,我們知道這些封裝好的類都是線程安全的工具類,可以直接在多線程環(huán)境下使用,說下getAndSet方法
public final int getAndSet(int newValue){ for( ;; ){ int current = get(); if(compareAndSet(current,newValue)){ return current; } } }
在這個方法中,我們并沒有看到synchronize關鍵字,代碼也很簡潔。關鍵的地方在與compareAndSet(current,newValue)這個方法的設計。在Java中它是一個本地方法,所以我們看不到它的具體實現(xiàn)。可以去google下查看具體的設計,這里我說下我的認識。如果有個變量 a = 1 此時有兩個線程同時執(zhí)行下面操作:
a = 1; a = 2;
為了下面可以方便簡單的描述問題,我們認為對變量的更改是原子性的,即不談Java的內(nèi)存模型問題或忽視線程可見問題。如果此時線程A和線程B同時進入getAndSet方法,用一段語言描述compareAndSet方法的執(zhí)行過程,可能是這樣子。
A線程讀取到current = 0; B線程讀取到current = 0; A執(zhí)行set方法,先去把自己current值和內(nèi)存中現(xiàn)有的值(我們把該值成為memory)比較,發(fā)現(xiàn) current = memory = 0, A線程更改 a 成功,此時memory = 1 這時B線程執(zhí)行set方法,則會有這樣的 current != memory ,B線程更新失敗。 于是B線程重新進行,此時獲取current = 1,在執(zhí)行set方法,current = memory = 1 ,OK B線程也執(zhí)行成功。 最終 memory = 2;
這種并發(fā)控制和上述悲觀鎖的并發(fā)控制方式,主要區(qū)別就是,沒有阻塞。它不會阻塞其它并發(fā)的操作行為,而是讓他們嘗試更新。這種嘗試的去更新的控制形式,我們叫它樂觀鎖。樂觀的說法就是體現(xiàn)在不會阻塞其它并發(fā)者。這種樂觀鎖在實際電商業(yè)務中則很常見,比如更新庫存,比如hibernate的樂觀鎖實現(xiàn)。
數(shù)據(jù)庫的悲觀鎖和樂觀鎖并發(fā)控制在數(shù)據(jù)庫中,以mysql的Innodb引擎為例,下面語句就是悲觀鎖的使用方式
start transaction; select * from message where id= 1 for update; update set … where id = 1; commit;
上述for update會鎖住id =1的這行數(shù)據(jù),它會阻塞其它連接查詢改行數(shù)據(jù)。在實際生成環(huán)境中卻很少使用。以電影院的售票系統(tǒng)來講,在用戶并發(fā)購買座位時,肯定會存在并發(fā)購買的問題。這時一般我們都會通過增加一個version字段來解決問題
start transaction; // ticket 代表電影票下的座位分布信息,status = 1 代表座位已經(jīng)被預定。 update ticket set `status` = 1 ,version = 1 where id =1 and version =0; commit;
這時version字段就相當于并發(fā)訪問下的版本控制如果有人預定version的字段就變?yōu)?,如果發(fā)現(xiàn)設置status字段為1時version不是1就更新失敗,這就是通過樂觀鎖的方式進行并發(fā)控制的一種方式。上述語句其實也可以不增加version字段,這里主要方便敘述問題,直接寫成下面這樣也OK
start transaction; update ticket set `status` = 1 where status = 0; commit;
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/65861.html
摘要:比如主協(xié)程啟動個子協(xié)程,主協(xié)程等待所有子協(xié)程退出后再繼續(xù)后續(xù)流程,這種場景下也可輕易實現(xiàn)。這個例子中,父協(xié)程僅僅是等待子協(xié)程結(jié)束,其實父協(xié)程也可以向管道中寫入數(shù)據(jù)通知子協(xié)程結(jié)束,這時子協(xié)程需要定期地探測管道中是否有消息出現(xiàn)。一.設計原理Go 語言中最常見的、也是經(jīng)常被人提及的設計模式就是:不要通過共享內(nèi)存來通信,我們應該使用通信來共享內(nèi)存通過共享內(nèi)存來通信是直接讀取內(nèi)存的數(shù)據(jù),而通過通信來共...
摘要:故事開始了,小程序圖片合成真機測試時,會報錯。所以只能將異步并發(fā)改為同步阻塞式渲染。 showImg(https://segmentfault.com/img/remote/1460000013228074); 故事開始了,小程序canvas圖片合成 真機測試時,會報錯:getImageInfo failed 。也就是說,我這邊異步請求50張圖片,每張圖片都是通過getImageInf...
摘要:而是在調(diào)用發(fā)出后,被調(diào)用者通過狀態(tài)通知來通知調(diào)用者,或通過回調(diào)函數(shù)處理這個調(diào)用。請求程序發(fā)出請求,從服務器端獲取數(shù)據(jù),并設置了回調(diào)函數(shù)。然后,瀏覽器會設置偵聽來自網(wǎng)絡的響應,拿到數(shù)據(jù)后,將該回調(diào)函數(shù)插入到事件循環(huán)。 并發(fā)與并行 并發(fā)是指兩個或多個事件鏈隨時間發(fā)展交替執(zhí)行,以至于從更高的層次來看,就像是同時運行(但在任意時刻只處理一個事件) 并發(fā)的關鍵是你有處理多個任務的能力,不一定同...
摘要:在接下來的分鐘,你將會學會如何通過同步關鍵字,鎖和信號量來同步訪問共享可變變量。所以在使用樂觀鎖時,你需要每次在訪問任何共享可變變量之后都要檢查鎖,來確保讀鎖仍然有效。 原文:Java 8 Concurrency Tutorial: Synchronization and Locks譯者:飛龍 協(xié)議:CC BY-NC-SA 4.0 歡迎閱讀我的Java8并發(fā)教程的第二部分。這份指南將...
閱讀 3835·2021-11-24 09:39
閱讀 3753·2021-11-22 12:07
閱讀 1105·2021-11-04 16:10
閱讀 798·2021-09-07 09:59
閱讀 1902·2019-08-30 15:55
閱讀 935·2019-08-30 15:54
閱讀 724·2019-08-29 14:06
閱讀 2475·2019-08-27 10:54