加鎖悲觀策略:
併發控制而言,鎖是一種悲觀策略,會阻塞線程執行,本質上是將併發轉變爲串行來實現的,勢必會影響吞吐量。並且線程的數量是有限的,依賴於操做系統,並且線程的建立和銷燬帶來的性能損耗是不能夠忽略掉的。雖然如今基本都是用線程池來儘量的下降不斷建立線程帶來的性能損耗。html
對數據被外界(包括本系統當前的其餘事務,以及來自外部系統的事務處理)修改持保守態度,所以,在整個數據處理過程當中,將數據處於鎖定狀態。悲觀鎖的實現,每每依靠數據庫提供的鎖機制(也只有數據庫層提供的鎖機制才能真正保證數據訪問的排他性,不然,即便在本系統中實現了加鎖機制,也沒法保證外部系統不會修改數據)。例如: select * from table_name where id = "xxx" for update
這樣查詢出來的這一行數據就被鎖定了,在這個update事務提交以前其餘外界是不能修改這條數據的,可是這種處理方式效率比較低,通常不推薦使用。算法
無鎖樂觀策略:
它會假設對資源的訪問時沒有衝突的,既然沒有衝突就不須要等待,線程不須要阻塞。那多個線程共同訪問臨界區的資源時,無鎖的策略採用一種比較交換技術CAS(compare and swap)來鑑別線程衝突,一旦檢測到衝突,就會重試當前操做指導沒有衝突爲止。數據庫
相對悲觀鎖而言,樂觀鎖機制採起了更加寬鬆的加鎖機制。悲觀鎖大多數狀況下依靠數據庫的鎖機制實現,以保證操做最大程度的獨佔性。但隨之而來的就是數據庫性能的大量開銷,特別是對長事務而言,這樣的開銷每每沒法承受。如一個金融系統,當某個操做員讀取用戶的數據,並在讀出的用戶數據的基礎上進行修改時(如更改用戶賬戶餘額),若是採用悲觀鎖機制,也就意味着整個操做過程當中(從操做員讀出數據、開始修改直至提交修改結果的全過程,甚至還包括操做員中途去煮咖啡的時間),數據庫記錄始終處於加鎖狀態,能夠想見,若是面對幾百上千個併發,這樣的狀況將致使怎樣的後果。
樂觀鎖機制在必定程度上解決了這個問題。樂觀鎖,大可能是基於數據版本( Version )記錄機制實現。何謂數據版本?即爲數據增長一個版本標識,在基於數據庫表的版本解決方案中,通常是經過爲數據庫表增長一個 「version」 字段來實現。讀取出數據時,將此版本號一同讀出,以後更新時,對此版本號加一。此時,將提交數據的版本數據與數據庫表對應記錄的當前版本信息進行比對,若是提交的數據版本號大於數據庫表當前版本號,則予以更新,不然認爲是過時數據。json
樂觀鎖的實現:併發
update account set field1 = ? and field2 = ? and version = version + 1 where version = ?app
與鎖相比,CAS會使得程序設計比較負責,可是因爲其優越的性能優點,以及天生免疫死鎖(根本就沒有鎖,固然就不會有線程一直阻塞了),更爲重要的是,使用無鎖的方式沒有所競爭帶來的開銷,也沒有線程間頻繁調度帶來的開銷,他比基於鎖的方式有更優越的性能,因此在目前被普遍應用,咱們在程序設計時也能夠適當的使用.框架
不過因爲CAS編碼確實稍微複雜,並且jdk做者自己也不但願你直接使用unsafe(後面會講到)來進行代碼的編寫,因此若是不能深入理解CAS以及unsafe仍是要慎用,使用一些別人已經實現好的無鎖類或者框架就行了。curl
一個CAS方法包含三個參數CAS(V,E,N)。V表示要更新的變量,E表示預期的值,N表示新值。只有當V的值等於E時,纔會將V的值修改成N。若是V的值不等於E,說明已經被其餘線程修改了,當前線程能夠放棄此操做,也能夠再次嘗試次操做直至修改爲功。基於這樣的算法,CAS操做即便沒有鎖,也能夠發現其餘線程對當前線程的干擾(臨界區值的修改),並進行恰當的處理。elasticsearch
_version : 第一次建立一個document的時候,_version內部的版本號就是1,之後的每個修改(包括刪除)都會加1ide
curl -XPUT 'localhost:9200/blog/post/8?pretty' -H 'Content-Type: application/json' -d'
{
"title": "My BBB first blog entry"
}'
{
"_index" : "blog",
"_type" : "post",
"_id" : "8",
"_version" : 1,
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"created" : true
}
update操做:下面至關於全量替換,
這個時候_version = _version+1
curl -XPUT 'localhost:9200/blog/post/8?pretty' -H 'Content-Type: application/json' -d'
{
"title": "My BBB first blog entry"
}'
{
"_index" : "blog",
"_type" : "post",
"_id" : "8",
"_version" : 2,
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"created" : false
}
刪除後_version = _version+1
curl -XDELETE 'localhost:9200/blog/post/8?pretty' -H 'Content-Type: application/json'
{
"found" : true,
"_index" : "blog",
"_type" : "post",
"_id" : "8",
"_version" : 3,
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
}
}
curl -XPUT 'localhost:9200/blog/post/8?pretty' -H 'Content-Type: application/json' -d'
{
"title": "My first blog entry add again"
}'
這時候的delete不是立馬物理刪除
版本控制攜帶version參數
官網說的很詳細:
https://www.elastic.co/guide/cn/elasticsearch/guide/current/optimistic-concurrency-control.html
curl -XGET 'localhost:9200/blog/post/8?pretty&version=4' { "_index" : "blog", "_type" : "post", "_id" : "8", "_version" : 4, "found" : true, "_source" : { "title" : "My first blog entry add again" } }