1. 理解同步和異步
同步:一件事一件事的做,做這件事的時候,不能干其他事情
異步:做一件事的同時,可以做其他事情。很多事情可以同時進行
2. 臟數據
當一個事務正在操作數據庫時,數據還沒有提交,這時,另外一個事務也訪問了這個數據庫,然后使用了這個數據,由于訪問的并不是最新的數據,那么這個讀取的操作可能是不正確的,讀到的這個數據就是“臟數據”。
3. 同步(synchronized)處理并發
在方法名前面加上synchronized關鍵字,或者使用同步鎖lock,即可實現同步。
原理:當A事務在處理這件事情的時候,其他的事務只能等待A事務處理完了才能進行處理。
優點:能簡單快速的處理并發問題
缺點:
1. 在單機中:由于A事務在進行,其他很多事務都要排隊等待,必將使得執行速度變慢,損耗性能。
2. 在分布式中:單個程序中事務的同步并不能使其他的程序事務進行等待,起不到應有的作用。
4. 悲觀鎖和樂觀鎖(針對于數據庫)
悲觀鎖:鎖定數據庫中當前事務要操作的數據,在該數據操作完成后,其他操作才能對數據庫進行訪問。
實現方法:在sql后面加上 for update或者for update nowait
for update和for update nowait區別:
1. for update 鎖定當前操作數據,其他事務等待
2. for update nowait鎖定當前數據,其他事務發現數據被鎖定,立即返回"ORA-00054錯誤,內容是資源正忙, 但指定以 NOWAIT 方式獲取資源"
例如:select * from account where name="何紅乾" for update
優點:無論是在單機還是分布式中,只要使用的是同一個數據庫,那么悲觀鎖就能起到作用。
缺點:鎖定數據后,必將影響其他操作,在大流量的情況下,操作速度變慢
樂觀鎖: 采取版本控制方法,只有當要修改的數據版本高于目前存儲的數據版本時,才能操作。
實現方法:在表中增加一個字段version,查詢表中數據時,獲取version版本號,版本號+1,修改表中數據時核對version版本號是否大于存儲的版本號,如果是則操作成功,否則失敗。
優點:可以多個事務同時進行,然后根據返回的不同結果做相應的操作,避免了長事務中的數據庫加鎖開銷。
缺點: 樂觀鎖機制往往基于系統中的數據存儲邏輯,因此也具備一定的局 限性,如在上例中,由于樂觀鎖機制是在我們的系統中實現,來自外部系統的用戶 余額更新操作不受我們系統的控制,因此可能會造成臟數據被更新到數據庫中。在 系統設計階段,我們應該充分考慮到這些情況出現的可能性,并進行相應調整(如 將樂觀鎖策略在數據庫存儲過程中實
現,對外只開放基于此存儲過程的數據更新途 徑,而不是將數據庫表直接對外公開)
5. redis緩存
1. redis不同于mysql,它是完全基于內存的,絕大部分請求是純粹的內存操作,非常快速。數據存在內存中,類似于HashMap,HashMap的優勢就是查找和操作的時間復雜度都是O(1);
2. 數據結構簡單,對數據操作也簡單,Redis中的數據結構是專門進行設計的;
3. 采用單線程,避免了不必要的上下文切換和競爭條件,也不存在多進程或者多線程導致的切換而消耗 CPU,不用去考慮各種鎖的問題,不存在加鎖釋放鎖操作,沒有因為可能出現死鎖而導致的性能消耗;
4. 使用多路I/O復用模型,非阻塞IO;
多路I/O復用模型:多路I/O復用模型是利用 select、poll、epoll 可以同時監察多個流的 I/O 事件的能力,在空閑的時候,會把當前線程阻塞掉,當有一個或多個流有 I/O 事件時,就從阻塞態中喚醒,于是程序就會輪詢一遍所有的流(epoll 是只輪詢那些真正發出了事件的流),并且只依次順序的處理就緒的流,這種做法就避免了大量的無用操作。
這里“多路”指的是多個網絡連接,“復用”指的是復用同一個線程。采用多路 I/O 復用技術可以讓單個線程高效的處理多個連接請求(盡量減少網絡 IO 的時間消耗),且 Redis 在內存中操作數據的速度非???,也就是說內存內的操作不會成為影響Redis性能的瓶頸,主要由以上幾點造就了 Redis 具有很高的吞吐量
5. 使用底層模型不同,它們之間底層實現方式以及與客戶端之間通信的應用協議不一樣,Redis直接自己構建了VM 機制 ,因為一般的系統調用系統函數的話,會浪費一定的時間去移動和請求;
6. redis分布式鎖(基于setnx(),expire()方法)
setnx(key,value),如果key不存在,則設置key-value成功,返回1;如果key存在,則返回0。
expire()設置過期時間
實現方法:
1. setnx(lockkey, 1) 如果返回 0,則說明占位失??;如果返回 1,則說明占位成功
2. expire() 命令對 lockkey 設置超時時間,為的是避免死鎖問題。
3. 執行完業務代碼后,可以通過 delete 命令刪除 key。
優點:簡單易實現,能解決日常工作需求。
缺點: 如果執行完setnx()方法后,在expire()方法執行前發生了宕機,那么就會出現死鎖。
7. redis分布式鎖(基于setnx(),get(),getset()方法)
get(key),獲取key對應的value。
getset(key,value1),返回null此時key的值會被設置為value1.
getset(key,value2),? 返回null此時key的值會被設置為value2.
實現方法:
1. setnx(lockkey, 當前時間+過期超時時間),如果返回 1,則獲取鎖成功;如果返回 0 則沒有獲取到鎖,則進行其他操作
2. get(lockkey) 獲取值 oldExpireTime ,并將這個 value 值與當前的系統時間進行比較,如果小于當前系統時間,則認為這個鎖已經超時,可以允許別的請求重新獲取,進行其他操作。
3. 計算 newExpireTime = 當前時間+過期超時時間,然后 getset(lockkey, newExpireTime) 會返回當前 lockkey 的值currentExpireTime。
4. 判斷 currentExpireTime 與 oldExpireTime 是否相等,如果相等,說明當前 getset 設置成功,獲取到了鎖。如果不相等,說明這個鎖又被別的請求獲取走了,那么當前請求可以直接返回失敗,或者繼續重試。
5. 在獲取到鎖之后,當前線程可以開始自己的業務處理,當處理完畢后,比較自己的處理時間和對于鎖設置的超時時間,如果小于鎖設置的超時時間,則直接執行 delete 釋放鎖;如果大于鎖設置的超時時間,則不需要再鎖進行處理。
優點:能夠防止setnx(),expire()方式出現的死鎖問題
缺點: 不太清楚