如何基于 String 实现同步锁?
作者:等你歸去來
https://www.cnblogs.com/yougewe/p/11573911.html
如何基于String實現同步鎖?
在某些時候,我們可能想基于字符串做一些事情,比如:針對同一用戶的并發同步操作,使用鎖字符串的方式實現比較合理。
因為只有在相同字符串的情況下,并發操作才是不被允許的。而如果我們不分青紅皂白直接全部加鎖,那么整體性能就下降得厲害了。
因為String的多樣性,看起來string鎖是天然比分段鎖之類的高級鎖更有優勢呢。
因為String 類型的變量賦值是這樣的:?String?a = "hello world."; 所有往往會有個錯誤的映象,String對象就是不可變的。
額,關于這個問題的爭論咱們就不細說了,總之, "a" != "a" 是有可能成立的。
另外,針對上鎖這件事,我們都知道,鎖是要針對同一個對象,才會有意義。所以,粗略的,我們可以這樣使用字符串鎖:
public?void?method1()?{??String?str1?=?"a";??synchronized?(str1)?{??//?do?sync?a?things...??}?? }??public?void?method2()?{??String?str2?=?"a";??synchronized?(str2)?{??//?do?sync?b?things...??}?? }??乍一看,這的確很方便簡單。但是,前面說了, "a" 是可能不等于 "a" 的(這是大部分情況,只有當String被存儲在常量池中時值相同的String變量才相等)。5個刁鉆的String面試題,推薦大家看下。
所以,我們可以稍微優化下:
public?void?method3()?{??String?str1?=?"a";??synchronized?(str1.intern())?{??//?do?sync?a?things...??}?? }??public?void?method4()?{??String?str2?=?"a";??synchronized?(str2.intern())?{??//?do?sync?b?things...??}?? }??看起來還是很方便簡單的,其原理就是把String對象放到常量池中。但是會有個問題,這些常量池的數據如何清理呢?
不管怎么樣,我們是不是可以自己去基于String實現一個鎖呢?關注微信公眾號:Java技術棧,在后臺回復:Java,可以獲取我整理的 N 篇 Java 教程,都是干貨。
肯定是可以的了!直接上代碼!
?
?
使用時,只需傳入 lockKey 即可。?
這樣做有什么好處嗎?
使用ConcurrentHashMap實現鎖獲取,性能還是不錯的;
每個字符串對應一個鎖,使用完成后就刪除,不會導致內存溢出問題;
可以作為一個外部工具使用,業務代碼接入方便,無需像 synchronized 一樣,需要整段代碼包裹起來;
本文只是想展示實現 String 鎖,此鎖并不適用于分布式場景下的并發處理;
擴展: 如果不使用 String 做鎖,如何保證大并發前提下的小概率并發場景的線程安全?
我們知道 CAS 的效率是比較高的,我們可以使用原子類來進行CAS的操作。
比如,我們添加一狀態字段, 操作此字段以保證線程安全:
/**??*?運行狀態??*?4:?正在刪除,?1:?正在放入隊列中,?0:?正常無運行??*/?? private?transient?volatile?AtomicInteger?runningStatus?=?new?AtomicInteger(0);??//?更新時先獲取該狀態:?? public?void?method5()?{??AtomicInteger?runningStatus?=?link.getRunningStatus();??//?正在刪除數據過程中,則等待??if(!runningStatus.compareAndSet(0,?1))?{??//?1.?等待另外線程刪除完成??//?2.?刪除正在更新標識??//?3.?重新運行本次數據放入邏輯??long?lockStartTime?=?System.currentTimeMillis();??long?maxLockTime?=?10?*?1000;??while?(!runningStatus.compareAndSet(0,?1))?{??if(System.currentTimeMillis()?-?lockStartTime?>?maxLockTime)?{??break;??}??}??runningStatus.compareAndSet(1,?0);??throw?new?RuntimeException("數據正在更新,重新運行:?"?+?link.getLinkKey()?+?link);??}??try?{??//?do?sync?things??}??finally?{??runningStatus.compareAndSet(1,?0);??}?? }??public?void?method6()?{??AtomicInteger?runningStatus?=?link.getRunningStatus();??if?(!runningStatus.compareAndSet(0,?4))?{??logger.error("?數據正在更新中,不得刪除,返回?");??return;??}??try?{??//?do?sync?things??}??catch?(Exception?e)?{??logger.error("并發更新異常:",?e);??}??finally?{??runningStatus.compareAndSet(4,?0);??}?? }??實際測試下來,CAS?性能是要比?synchronized?之類的鎖性能要好的。
當然,我們這里針對的并發數都是極少的,我們只是想要保證這極少情況下的線程安全性。所以,其實也還好。
總結
以上是生活随笔為你收集整理的如何基于 String 实现同步锁?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微服务把我坑了!
- 下一篇: 开源的13个Spring Boot 优秀