3
我有原來的同步代碼,CompletableFuture和鎖
Lock lock = getLock(userId); // get a lock from guava Striped locks
lock.lock();
try {
// do some database writing action
updateUserByUserId(userId);
return updateUserPropertiesByUserId(userId);
}
finally {
lock.unlock();
}
鎖的目的是在一個更高的水平,以模仿悲觀數據庫鎖定。
在Java8中,引入了CompleteableFutures。 updateUserByUserId(userId);
和updateUserPropertiesByUserId(userId);
現在可以返回CompletableFuture<Void>
以完全異步執行。
我的問題是,我怎樣才能使用相同的機制?或者這種鎖定方式完全錯誤? (我真的不希望依賴於數據庫的鎖定。如果可能的話,我想在應用程序層而不是數據庫層來處理這個)
我已經試過
Lock lock = getLock(userId); // get a lock from guava Striped locks
return CompletableFuture
.supplyAsync(() -> {
lock.lock();
})
.thenCompose(VOID -> updateUserByUserId(userId))
.thenCompose(entity -> updateUserPropertiesByUserId(userId))
.whenComplete((entity, ex) -> {
lock.unlock();
});
但我可一直在IllegalMonitorStateException
lock.unlock();
,這是預期的,因爲你不應該解鎖在另一個線程的鎖。
有什麼建議嗎?
你的鎖在這裏模仿*悲觀*鎖定,不樂觀。我不明白爲什麼你不會依賴數據庫事務和鎖定。如果您的應用程序有多個實例正在運行,或者其他人正在訪問同一個數據庫,那麼您的鎖定機制將不起作用。 –
你說的樂觀是對的。我已經改變它說悲觀。 這是一個簡單的例子來證明我正在嘗試做什麼。實際上,我的數據庫只有1個訪問器,這是我的微服務只有1個接口。在主動 - 主動設置中,將使用從緩存層檢索到的鎖。 爲什麼我試圖這樣做是因爲我想「快速失敗,提前失敗」而不是採取另一跳到數據庫,這將引發錯誤,讓應用層將數據庫錯誤轉換爲異常,然後趕上那個例外。這是一個很大的打擊。 – IsenGrim
而數據庫錯誤轉換爲Java異常可能因數據庫不同而不同......甚至是同一數據庫的不同風格。如果可能,我真的不想處理。 – IsenGrim