首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 5 線程新特性:ReadWriteLock 讀寫鎖優化並發性能(下)

     編輯:Java 相關知識

讀寫鎖核心思想

ReadWriteLock 維護一對鎖:

  • 讀鎖(共享鎖):多線程可同時持有,適合高頻讀操作
  • 寫鎖(排他鎖):獨佔,寫寫、讀寫互斥

核心規則:讀讀不互斥,讀寫互斥,寫寫互斥。大幅提升「讀多寫少」場景吞吐。

代碼示例:賬戶查詢用讀鎖,轉賬用寫鎖

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Test {
    public static void main(String[] args) {
        MyCount myCount = new MyCount("95599200901215522", 10000);
        ReadWriteLock lock = new ReentrantReadWriteLock(false); // 非公平
        ExecutorService pool = Executors.newFixedThreadPool(2);
        
        pool.execute(new User("張三", myCount, -4000, lock, false)); // 寫
        pool.execute(new User("張三他爹", myCount, 6000, lock, false)); // 寫
        pool.execute(new User("張三他弟", myCount, -8000, lock, false)); // 寫
        pool.execute(new User("張三", myCount, 800, lock, false)); // 寫
        pool.execute(new User("張三他爹", myCount, 0, lock, true));  // 讀
        pool.shutdown();
    }
}

class User implements Runnable {
    private String name; private MyCount myCount; private int iocash; 
    private ReadWriteLock myLock; private boolean ischeck;
    User(String name, MyCount myCount, int iocash, ReadWriteLock myLock, boolean ischeck) {
        this.name = name; this.myCount = myCount; this.iocash = iocash; 
        this.myLock = myLock; this.ischeck = ischeck;
    }
    public void run() {
        if (ischeck) { // 查詢操作:讀鎖
            myLock.readLock().lock();
            try {
                System.out.println("讀:" + name + "正在查詢" + myCount + "賬戶,當前金額為" + myCount.getCash());
            } finally { myLock.readLock().unlock(); }
        } else { // 修改操作:寫鎖
            myLock.writeLock().lock();
            try {
                System.out.println("寫:" + name + "正在操作" + myCount + "賬戶,金額為" + iocash + ",當前金額為" + myCount.getCash());
                myCount.setCash(myCount.getCash() + iocash);
                System.out.println("寫:" + name + "操作" + myCount + "賬戶成功,金額為" + iocash + ",當前金額為" + myCount.getCash());
            } finally { myLock.writeLock().unlock(); }
        }
    }
}

class MyCount {
    private String oid; private int cash;
    MyCount(String oid, int cash) { this.oid = oid; this.cash = cash; }
    public int getCash() { return cash; }
    public void setCash(int cash) { this.cash = cash; }
    @Override public String toString() { return "MyCount{oid='" + oid + "', cash=" + cash + '}'; }
}

運行結果

寫:張三正在操作MyCount{oid='95599200901215522', cash=10000}賬戶,金額為-4000,當前金額為10000
寫:張三操作MyCount{oid='95599200901215522', cash=6000}賬戶成功,金額為-4000,當前金額為6000
寫:張三他弟正在操作MyCount{oid='95599200901215522', cash=6000}賬戶,金額為-8000,當前金額為6000
寫:張三他弟操作MyCount{oid='95599200901215522', cash=-2000}賬戶成功,金額為-8000,當前金額為-2000
寫:張三正在操作MyCount{oid='95599200901215522', cash=-2000}賬戶,金額為800,當前金額為-2000
寫:張三操作MyCount{oid='95599200901215522', cash=-1200}賬戶成功,金額為800,當前金額為-1200
讀:張三他爹正在查詢MyCount{oid='95599200901215522', cash=-1200}賬戶,當前金額為-1200
寫:張三他爹正在操作MyCount{oid='95599200901215522', cash=-1200}賬戶,金額為6000,當前金額為-1200
寫:張三他爹操作MyCount{oid='95599200901215522', cash=4800}賬戶成功,金額為6000,當前金額為4800
Process finished with exit code 0

觀察:查詢(讀鎖)在寫操作間隙執行,多查詢可並發。若用普通鎖,查詢會阻塞寫入,反之亦然。

進階特性與選型建議

  • 鎖降級:持有寫鎖 → 獲取讀鎖 → 釋放寫鎖(允許),反之不允許
  • 公平策略:new ReentrantReadWriteLock(true) 公平模式,按請求順序授予
  • 性能對比:讀多寫少場景,ReadWriteLock 吞吐遠超 ReentrantLock
  • 適用場景:緩存、配置表、數據庫讀多寫少業務
  • 避坑:寫操作頻繁時,讀寫鎖開銷大於普通鎖

出處:https://lavasoft.blog.51cto.com/62575/222433

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved