當前位置:首頁 » 編程語言 » java的鎖實現

java的鎖實現

發布時間: 2022-09-21 01:00:03

A. java編程同步,加鎖如何實現,有何優缺點

同步鎖「synchronize」,手動鎖Lock

  • synchronize:自動鎖住,自動開鎖。(自動都是建立在一定的條件上的)

  • Lock:手動,手動鎖住,手動開鎖

具體如何實現,這里不好說,一時說不清,自行搜索。

B. 如何在Java中使用雙重檢查鎖實現單例

一個常見情景,單例類在多線程環境中違反契約。如果你要一個新手寫出單例模式,可能會得到下面的代碼:
private static Singleton _instance;

public static Singleton getInstance() {
if (_instance == null) {
_instance = new Singleton();
}
return _instance;
}

然後,當你指出這段代碼在超過一個線程並行被調用的時候會創建多個實例的問題時,他很可能會把整個getInstance()方法設為同步(synchronized),就像我們展示的第二段示例代碼getInstanceTS()方法一樣。盡管這樣做到了線程安全,並且解決了多實例問題,但並不高效。在任何調用這個方法的時候,你都需要承受同步帶來的性能開銷,然而同步只在第一次調用的時候才被需要,也就是單例類實例創建的時候。這將促使我們使用雙重檢查鎖模式(double checked locking pattern),一種只在臨界區代碼加鎖的方法。程序員稱其為雙重檢查鎖,因為會有兩次檢查 _instance == null,一次不加鎖,另一次在同步塊上加鎖。這就是使用Java雙重檢查鎖的示例:
public static Singleton getInstanceDC() {
if (_instance == null) { // Single Checked
synchronized (Singleton.class) {
if (_instance == null) { // Double checked
_instance = new Singleton();
}
}
}
return _instance;
}

這個方法表面上看起來很完美,你只需要付出一次同步塊的開銷,但它依然有問題。除非你聲明_instance變數時使用了volatile關鍵字。沒有volatile修飾符,可能出現Java中的另一個線程看到個初始化了一半的_instance的情況,但使用了volatile變數後,就能保證先行發生關系(happens-before relationship)。對於volatile變數_instance,所有的寫(write)都將先行發生於讀(read),在Java 5之前不是這樣,所以在這之前使用雙重檢查鎖有問題。現在,有了先行發生的保障(happens-before guarantee),你可以安全地假設其會工作良好。另外,這不是創建線程安全的單例模式的最好方法,你可以使用枚舉實現單例模式,這種方法在實例創建時提供了內置的線程安全。另一種方法是使用靜態持有者模式(static holder pattern)。
/*
* A journey to write double checked locking of Singleton class in Java.
*/

class Singleton {

private volatile static Singleton _instance;

private Singleton() {
// preventing Singleton object instantiation from outside
}

/*
* 1st version: creates multiple instance if two thread access
* this method simultaneously
*/

public static Singleton getInstance() {
if (_instance == null) {
_instance = new Singleton();
}
return _instance;
}

/*
* 2nd version : this definitely thread-safe and only
* creates one instance of Singleton on concurrent environment
* but unnecessarily expensive e to cost of synchronization
* at every call.
*/

public static synchronized Singleton getInstanceTS() {
if (_instance == null) {
_instance = new Singleton();
}
return _instance;
}

/*
* 3rd version : An implementation of double checked locking of Singleton.
* Intention is to minimize cost of synchronization and improve performance,
* by only locking critical section of code, the code which creates instance of Singleton class.
* By the way this is still broken, if we don't make _instance volatile, as another thread can
* see a half initialized instance of Singleton.
*/

public static Singleton getInstanceDC() {
if (_instance == null) {
synchronized (Singleton.class) {
if (_instance == null) {
_instance = new Singleton();
}
}
}
return _instance;
}
}

這就是本文的所有內容了。這是個用Java創建線程安全單例模式的有爭議的方法,使用枚舉實現單例類更簡單有效。我並不建議你像這樣實現單例模式,因為用Java有許多更好的方式。但是,這個問題有歷史意義,也教授了並發是如何引入一些微妙錯誤的。正如之前所說,這是面試中非常重要的一點。
在去參加任何Java面試之前,要練習手寫雙重檢查鎖實現單例類。這將增強你發現Java程序員們所犯編碼錯誤的洞察力。另外,在現在的測試驅動開發中,單例模式由於難以被模擬其行為而被視為反模式(anti pattern),所以如果你是測試驅動開發的開發者,最好避免使用單例模式。轉載,僅供參考。

C. java怎麼實現redis分布式鎖

Redis有一系列的命令,特點是以NX結尾,NX是Not eXists的縮寫,如SETNX命令就應該理解為:SET if Not eXists。這系列的命令非常有用,這里講使用SETNX來實現分布式鎖。

用SETNX實現分布式鎖

利用SETNX非常簡單地實現分布式鎖。例如:某客戶端要獲得一個名字foo的鎖,客戶端使用下面的命令進行獲取:

SETNX lock.foo <current Unix time + lock timeout + 1>

如返回1,則該客戶端獲得鎖,把lock.foo的鍵值設置為時間值表示該鍵已被鎖定,該客戶端最後可以通過DEL lock.foo來釋放該鎖。
如返回0,表明該鎖已被其他客戶端取得,這時我們可以先返回或進行重試等對方完成或等待鎖超時。
解決死鎖

上面的鎖定邏輯有一個問題:如果一個持有鎖的客戶端失敗或崩潰了不能釋放鎖,該怎麼解決?我們可以通過鎖的鍵對應的時間戳來判斷這種情況是否發生了,如果當前的時間已經大於lock.foo的值,說明該鎖已失效,可以被重新使用。

發生這種情況時,可不能簡單的通過DEL來刪除鎖,然後再SETNX一次,當多個客戶端檢測到鎖超時後都會嘗試去釋放它,這里就可能出現一個競態條件,讓我們模擬一下這個場景:

C0操作超時了,但它還持有著鎖,C1和C2讀取lock.foo檢查時間戳,先後發現超時了。
C1 發送DEL lock.foo
C1 發送SETNX lock.foo 並且成功了。
C2 發送DEL lock.foo
C2 發送SETNX lock.foo 並且成功了。
這樣一來,C1,C2都拿到了鎖!問題大了!

幸好這種問題是可以避免D,讓我們來看看C3這個客戶端是怎樣做的:

C3發送SETNX lock.foo 想要獲得鎖,由於C0還持有鎖,所以Redis返回給C3一個0
C3發送GET lock.foo 以檢查鎖是否超時了,如果沒超時,則等待或重試。
反之,如果已超時,C3通過下面的操作來嘗試獲得鎖:
GETSET lock.foo <current Unix time + lock timeout + 1>
通過GETSET,C3拿到的時間戳如果仍然是超時的,那就說明,C3如願以償拿到鎖了。
如果在C3之前,有個叫C4的客戶端比C3快一步執行了上面的操作,那麼C3拿到的時間戳是個未超時的值,這時,C3沒有如期獲得鎖,需要再次等待或重試。留意一下,盡管C3沒拿到鎖,但它改寫了C4設置的鎖的超時值,不過這一點非常微小的誤差帶來的影響可以忽略不計。
注意:為了讓分布式鎖的演算法更穩鍵些,持有鎖的客戶端在解鎖之前應該再檢查一次自己的鎖是否已經超時,再去做DEL操作,因為可能客戶端因為某個耗時的操作而掛起,操作完的時候鎖因為超時已經被別人獲得,這時就不必解鎖了。

示例偽代碼

根據上面的代碼,我寫了一小段Fake代碼來描述使用分布式鎖的全過程:

# get lock
lock = 0
while lock != 1:
timestamp = current Unix time + lock timeout + 1
lock = SETNX lock.foo timestamp
if lock == 1 or (now() > (GET lock.foo) and now() > (GETSET lock.foo timestamp)):
break;
else:
sleep(10ms)

# do your job
do_job()

# release
if now() < GET lock.foo:
DEL lock.foo
是的,要想這段邏輯可以重用,使用python的你馬上就想到了Decorator,而用Java的你是不是也想到了那誰?AOP + annotation?行,怎樣舒服怎樣用吧,別重復代碼就行。

D. JAVA中的內鎖機制是什麼

多線程同步的實現最終依賴鎖機制。我們可以想像某一共享資源是一間屋子,每個人都是一個線程。當A希望進入房間時,他必須獲得門鎖,一旦A獲得門鎖,他進去後就立刻將門鎖上,於是B,C,D...就不得不在門外等待,直到A釋放鎖出來後,B,C,D...中的某一人搶到了該鎖(具體搶法依賴於JVM的實現,可以先到先得,也可以隨機挑選),然後進屋又將門鎖上。這樣,任一時刻最多有一人在屋內(使用共享資源)。 Java語言規范內置了對多線程的支持。對於Java程序來說,每一個對象實例都有一把「鎖」,一旦某個線程獲得了該鎖,別的線程如果希望獲得該鎖,只能等待這個線程釋放鎖之後。獲得鎖的方法只有一個,就是synchronized關鍵字。

E. java分布式鎖的實現方式有哪些

之前在itjob技術群討論過這個1、資料庫級別控制,樂觀鎖控制2、類似zookeeper做一個遠程單點鎖,每次取鎖、加鎖、釋放鎖
還有沒有更優解,上面兩種哪個好點
簡單說就是http請求,100ms內兩個同樣的請求,{查詢介面拿一個key和一個數值,然後+1,請求新數值},加{}的這個過程希望相同key的請求能夠串列,否則設置新值會有並發問題

F. java多線程『鎖』,是用什麼鎖的,有方法

多線程的同步鎖通過synchronized實現

有倆種方式 一種是在代碼塊加鎖
代碼塊加鎖時可以指定任意類的實例過的對象
即鎖在這個對象上(任何對象都有一個鎖)
使同一時間內只有一個線程可以訪問到代碼塊中

另外一種就是以synchronized關鍵字修飾方法
這時加鎖的對象就是類本身的實例 即this

以上 O(∩_∩)O

G. java怎麼實現redis分布式鎖

一、使用分布式鎖要滿足的幾個條件:

系統是一個分布式系統(關鍵是分布式,單機的可以使用ReentrantLock或者synchronized代碼塊來實現)
共享資源(各個系統訪問同一個資源,資源的載體可能是傳統關系型資料庫或者Nosql
同步訪問(即有很多個進程同事訪問同一個共享資源。沒有同步訪問,誰管你資源競爭不競爭)
二、應用的場景例子

管理後台的部署架構(多台tomcat伺服器+redis【多台tomcat伺服器訪問一台redis】+mysql【多台tomcat伺服器訪問一台伺服器上的mysql】)就滿足使用分布式鎖的條件。多台伺服器要訪問redis全局緩存的資源,如果不使用分布式鎖就會出現問題。 看如下偽代碼:

long N=0L;
//N從redis獲取值
if(N<5){
N++;
//N寫回redis
}
復制代碼

H. JAVA編程同步,加鎖如何實現,有何優缺點

加鎖的方式有非常多,可以在程序上使用。或者是在資料庫上操作。保證事務一致性即可

I. Java 集群鎖如何實現

1. 用資料庫,在資料庫建一張表,需要鎖的節點都可以嘗試用 select * from Lock where id=xx for update. 這個時候只有一個節點能拿到結果,其它的都會等待,就能實現一個簡單的悲觀鎖。
2. 用 Zookeeper 來做分布式鎖,具體可以搜一下。
3. 自己實現,搞個節點來做這個事情,所有要獲取鎖的都走 RPC 調用來請求鎖,用完以後記得釋放,不然其他的節點就會掛那裡。

熱點內容
圖的演算法java 發布:2025-01-11 05:57:07 瀏覽:480
梯形圖編譯器 發布:2025-01-11 05:56:26 瀏覽:258
安卓framework編譯 發布:2025-01-11 05:55:00 瀏覽:694
加密學原理 發布:2025-01-11 05:54:20 瀏覽:786
ocr編程 發布:2025-01-11 05:51:24 瀏覽:252
androiddecoder 發布:2025-01-11 05:44:13 瀏覽:730
蘇州數控編程培訓 發布:2025-01-11 05:42:51 瀏覽:855
編程式控制制小船 發布:2025-01-11 05:35:05 瀏覽:757
螢石雲清理緩存 發布:2025-01-11 05:34:29 瀏覽:779
怎麼在電腦上傳照片 發布:2025-01-11 05:30:20 瀏覽:488