房間裏燈光昏暗,兩個男人相對而坐,java
良久,眼睛男率先打破僵局,mysql
眼睛男,知道鎖麼程序員
帥氣男,知道些,web
眼睛男:什麼是鎖?sql
一種保護機制,在多線程的狀況下,保證操做數據的正確性/一致性,數據庫
眼鏡男:有哪幾種分類?緩存
悲觀鎖,樂觀鎖,獨佔鎖,共享鎖,公平鎖,非公平鎖,分佈式鎖,自旋鎖安全
眼睛男:講講樂觀鎖悲觀鎖吧多線程
通常喜歡放在數據庫來說(其實這兩個概念是屬於計算機的,不要被誤導),就說mysql吧,悲觀鎖,主要是表鎖,行鎖還有間隙鎖,葉鎖,讀鎖,由於這些鎖在被觸發的時候勢必引發線程阻塞,因此叫悲觀併發
另外樂觀鎖其實在mysql自己中不存在的,可是mysql提供了種mvcc的機制,支持樂觀鎖機制,
眼睛男:mvcc是咋回事?
只是在innodb引擎下存在,mvcc是爲了知足事務的隔離,經過版本號的方式,避免同一數據不一樣事務間的競爭,所說的樂觀鎖只在事務級別爲讀未提交讀提交,纔會生效,
眼睛男:具體mvcc機制有什麼?
多版本併發控制,保證數據操做在多線程過程當中,保證事務隔離的機制,能夠下降鎖競爭的壓力,保證比較高併發量,這個過程。在每開啓一個事務時,會生成一個事務的版本號,被操做的數據會生成一條新的數據行(臨時),可是在提交前對其餘事務是不可見的,對於數據的更新操做成功,會將這個版本號更新到數據的行中,事務提交成功,將新的版本號,更新到此數據行(永久)中,這樣保證了每一個事務操做的數據,都是相互不影響的,也不存在鎖的問題;
眼睛男:那麼在多個事務(操做同一條數據)併發過程當中,誰先成功?
mysql判斷,其實就是誰先提交成功算誰的
眼睛男:說到事務了,聊聊事務
事務常說一系列操做做爲一個總體要麼都成功要麼都失敗,主要特性acid,事務的的實現主要依賴兩個log redo-log,undo-log,每次事務都會記錄數據修改前的數據undo-log,修改後的數據放入redo-log,提出成功則使用redo-log 更新到磁盤,失敗則使用undo-log將數據恢復到事務以前的數據
眼鏡男,嗯,再說說獨佔鎖,共享鎖吧
(嗯,獨佔,共享,公平,非公平,自旋鎖這些都是普遍的概念,不少語言都有,包括操做系統,js的同窗請回避)
獨佔鎖很明顯就是持鎖的線程只能有一個,共享鎖則能夠有多個
眼睛男:獨佔能夠理解,共享的意義在哪裏?
共享鎖是爲了提升程序的效率,舉個例子數據的操做有讀寫之分,對於寫的操做加鎖,保證數據正確性,而對於讀的操做若是不加鎖,在寫讀操做同時進行時,讀的數據有可能不是最新數據,若是對讀操做加獨佔鎖,面對讀多寫少的程序確定效率很低,全部就出現了共享鎖,對於讀的的操做就使用共享的概念,可是對於寫的操做則是互斥的,保證了讀寫的數據操做都一致,在java中上述的鎖叫讀寫鎖
眼睛男:讀寫鎖的機制是什麼呢?(佯攻)
在java中讀寫鎖(ReadWritelock)的機制是基於AQS的一種實現,保證讀讀共享,讀寫互斥,寫寫互斥,若是要說機制的話,還要從AQS提及,這是java實現的一種鎖機制,互斥鎖,讀者寫鎖,條件產量,信號量,柵欄的都是它的衍生物,主要工做基於CHL隊列,voliate關鍵字修飾的狀態符stat,線程去修改狀態符成功了就是獲取成功,失敗了就進隊列等待,等待喚醒,AQS中還有很重要的一個概念是自旋,在等待喚醒的時候,不少時候會使用自旋(while(!cas()))的方式,不停的嘗試獲取鎖,直到被其餘線程獲取成功
共享與獨佔的區別就在於,CHL隊列中的節點的模式是EXCLUSIVE仍是SHARED,當一個線程成功修改了stat狀態,表示獲取了鎖,若是線程所在的節點爲SHARED,將開始一個讀鎖傳遞的過程,從頭結點,向隊列後續節點傳遞喚醒,直到隊列結束或者遇到了EXCLUSIVE的節點,等待全部激活的讀操做完成,而後進入到獨享模式(這部分盡力了,你們仍是看源碼)
公平與非公平的區別就在於線程第一次獲取鎖時,也就是執行修改stat操做時,是進隊列仍是直接修改狀態,這是基本的工做機制,詳細的估計能夠再聊好幾集
眼睛男:java 除了AQS 還有其餘的鎖支持麼
在java中,synchronized關鍵字,是語言自帶的,也叫內置鎖,synchronized關鍵字,咱們都知道被synchronized修飾的方法或者代碼塊,在同一時間內,只容許一個線程執行,是明顯的獨享鎖,synchronized的實現機制?能夠參考AQS的實現方式,只是AQS使用顯示的用lock.lock調用,而sync做爲關鍵字修飾,你能夠認爲在synchronized修飾的地方,自動添加了lock方法,結束的地方進行了unlock釋放鎖的方法,只是被隱藏了,咱們看不到。
它自己實現有兩部分:monitor對象,線程,工做機制仍是線程搶佔對象使用權,對象都有本身的對象頭,存儲了對象的不少信息,其中有一個是標識被哪一個線程持有,對比AQS,線程從修改stat,變爲修改monitor的對象頭,線程的等待區域動 AQS中的隊列,變爲monitor對象中的某個區域。
眼睛男:能細說麼?
導演,他本身加戲
導演:按照劇原本
鎖一直是圍繞線程安全來實現的,好比獨佔鎖,它在內存裏面的操做是怎麼樣的
這個地方涉及到一個概念,內存模型(這個和jvm不要混淆,The Java memory model used internally in the JVM divides memory between thread stacks and the heap. This diagram illustrates the Java memory model from a logic perspective),是JVM用來區別線程棧和堆的內存方式,每一個線程在運行的時候,所操做的數據存儲空間有兩個,一個是主內存一個是工做內存,主內存其實就是jvm中堆,工做內存就是線程的棧,每次的數據操做,都是從主內存中把數據讀到工做內存中,而後在工做內存中進行各類處理,若是進行了修改,會把數據回寫到主內存,而後其餘線程又進行一樣的操做,就這樣數據在工做內存和主內存,進進出出,不亦樂乎,在屢次的狀況下,就是由於進進出出的順序亂了,不是按照線程預期的訪問順序,就出現了數據不一致的問題,致使了多線程的不安全性;整個操做過程還牽涉到CPU,高速緩存等概念,略過。。。。
眼睛男:內存模型 還有哪些能夠聊聊的
happen-befor 原則,Volatile 關鍵字(線程的可見性),內存屏障
眼睛男:哦(慫了慫了)
happen-befor原則定義了內存模型執行過程當中的定律,就像1+1 = 2,不可能被打破的jvm的運行機制都依賴於這個原則,是jvm的憲法!!!
Volatile關鍵字就有點叼了,Volatile修飾的數據,在被某個線程修改後,會被及時的回寫到主內存,而後其餘線程再獲取時,就是新的數據,聽起來很美好,可是Volatile沒有辦法控制線程的順序,當一個數據(新數據)即將被修改到主內存時,恰好,另一個線程從主內存讀了數據(老數據),並又進行了一波操做,又將數據(更新的數據)回寫到了主內存,整個過程(新數據)徹底沒有起到一毛錢做用,最終致使了數據的錯誤,呼呼打完收工!!!!