日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java实现表锁行锁

發布時間:2024/10/5 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java实现表锁行锁 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

背景

今天做需求時遇到一個統計場景,接口將用戶請求記錄緩存在concurrentHashmap,其中用戶名作為map的Key,value為統計結果類的對象,更新此map的時候使用分段鎖(通過用戶名取hash值定位對應的鎖)確保在相對良好性能下使得value更新線程安全。此外通過定時任務2秒一次將緩存的map保存到redis數據庫后再清空map,這意味著定時任務執行的某個時候需要暫停所有寫入map操作,由于map寫入是使用分段鎖,意味著需要阻塞所有獲取分段鎖線程,類似于mysql某些修改表結構的時候會阻塞行鎖一樣。查閱資料后發現java并無相關實現,這里手動實現一個。

分段獨占鎖

  • 首先實現分段獨占鎖,在表-行鎖中充當行鎖的功能
  • 代碼如下,通過對key取hash值來定位具體的某行(鎖)
  • public class SegReentrantLock{private List<Lock> lockList;public SegReentrantLock() {this(10);}public SegReentrantLock(int size) {if (size < 1){throw new IllegalArgumentException("size must great than 0");}this.lockList = new ArrayList<>(size);for (int i = 0; i < size; i++) {this.lockList.add( new ReentrantLock() );}}public void lock(String key){int lockIndex = this.getLockIndex(key);this.lockList.get(lockIndex).lock();}public void unlock(String key){int lockIndex = this.getLockIndex(key);this.lockList.get(lockIndex).unlock();}private int getLockIndex(String key){int lockIndex = key.hashCode() % this.lockList.size();return Math.abs(lockIndex);}public boolean tryLock(String key, long time, TimeUnit timeUnit) throws InterruptedException {int lockIndex = key.hashCode() % this.lockList.size();if (time < 1 || timeUnit == null){return this.lockList.get(lockIndex).tryLock();}return this.lockList.get(lockIndex).tryLock(time, timeUnit);}public boolean tryLock(String key) throws InterruptedException {return this.tryLock(key, 0, TimeUnit.SECONDS);} }

    行表鎖

  • 在實現了分段鎖的基礎上,通過jdk自帶StampedLock來模擬表鎖。
  • 獲取行鎖的時候,先獲取StampedLock的讀鎖,再獲取行鎖,釋放同理
  • 獲取表鎖的時候,直接獲取StampedLock的寫鎖即可,如對性能有高要求,需減少獲取表鎖的饑餓現象,可通過StampedLock的tryOptimisticRead方法將加鎖邏輯修改為“讀的過程中也允許獲取寫鎖后寫入”的模式。
  • 行表鎖代碼如下
  • public class TableRowsLock {//表鎖private final StampedLock STAMPED_LOCK = new StampedLock();//行鎖private SegReentrantLock rowLocks;public TableRowsLock() {this(10);}public TableRowsLock(int rows) {rowLocks = new SegReentrantLock(rows);}/*** @description:釋放表鎖* @param time* @param timeUnit* @return long 時間戳,為0表示加鎖失敗*/public long tryLockTable(int time, TimeUnit timeUnit) throws InterruptedException {return STAMPED_LOCK.tryWriteLock(time, timeUnit);}public long tryLockTable() throws InterruptedException {return STAMPED_LOCK.tryWriteLock(0, TimeUnit.SECONDS);}/*** @description:釋放表鎖* @param stamp 獲取表鎖返回的時間戳* @see #tryLockTable(int, TimeUnit) * @return void*/public void unLockTable(long stamp){STAMPED_LOCK.unlockWrite(stamp);}/*** @description:加行鎖* @param key* @param time* @param timeUnit* @return long 時間戳,為0表示加鎖失敗*/public long tryLockRow(String key, int time, TimeUnit timeUnit) throws InterruptedException {//先設置表鎖為已讀狀態long stamp = STAMPED_LOCK.tryReadLock(time, timeUnit);//失敗,直接返回if (stamp == 0) return stamp;//鎖行boolean lockedRow = rowLocks.tryLock(key, time, timeUnit);if (!lockedRow){STAMPED_LOCK.unlockRead(stamp);return 0;}return stamp;}public long tryLockRow(String key) throws InterruptedException {return tryLockRow(key, 0, TimeUnit.SECONDS);}/*** @description:釋放行鎖* @param key* @param stamp 獲取行鎖獲得的時間戳* @see #tryLockRow(String, int, TimeUnit)*/public void unlockRow(String key, long stamp){STAMPED_LOCK.unlockRead(stamp);rowLocks.unlock(key);} }

    測試代碼

    public static void main(String[] args) {//測試行鎖釋放和未釋放情況下獲取表鎖testBlockingTableLock();//測試表鎖釋放和未釋放情況下獲取行鎖 // testBlockingRowLock();}//測試行鎖釋放和未釋放情況下獲取表鎖private static void testBlockingTableLock(){TableRowsLock tableLock = new TableRowsLock(2);new Thread(() -> {try {long stamp1 = tableLock.tryLockRow("1");System.out.println("未加表鎖與行鎖時獲取行鎖1,結果:" + stamp1);long stamp2 = tableLock.tryLockRow("2");System.out.println("未加表鎖只加行鎖時獲取行鎖2,結果:" + stamp2);TimeUnit.SECONDS.sleep(2);//釋放行鎖tableLock.unlockRow("1", stamp1);tableLock.unlockRow("2", stamp2);} catch (Exception ex){ex.printStackTrace();}}).start();new Thread(() -> {try {TimeUnit.MILLISECONDS.sleep(500);//獲取表鎖long stamp = tableLock.tryLockTable();System.out.println("行鎖未釋放,獲取表鎖,結果:" + stamp);TimeUnit.SECONDS.sleep(3);stamp = tableLock.tryLockTable();System.out.println("行鎖全部釋放后 再次獲取表鎖,結果:" + stamp);} catch (InterruptedException e) {e.printStackTrace();}}).start();}//測試表鎖釋放和未釋放情況下獲取行鎖private static void testBlockingRowLock(){TableRowsLock tableLock = new TableRowsLock(2);new Thread(() -> {try {long stamp = tableLock.tryLockTable();System.out.println("未加行鎖時獲取表鎖,結果:" + stamp);TimeUnit.SECONDS.sleep(2);//釋放表鎖tableLock.unLockTable(stamp);} catch (Exception ex){ex.printStackTrace();}}).start();new Thread(() -> {try {TimeUnit.MILLISECONDS.sleep(500);//獲取行鎖long stamp = tableLock.tryLockRow("1");System.out.println("表鎖未釋放,獲取行鎖,結果:" + stamp);//表鎖釋放后獲取行鎖TimeUnit.SECONDS.sleep(3);stamp = tableLock.tryLockRow("1");System.out.println("表鎖釋放后,再次獲取行鎖,結果:" + stamp);} catch (Exception e) {e.printStackTrace();}}).start();}

    總結

    以上是生活随笔為你收集整理的java实现表锁行锁的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。