Java多线程并发编程 — 读写锁 Reentrant Read Write Lock ReentrantReadWriteLock 实现 interface ReadWriteLock: public interface ReadWriteLock { /** * Returns the lock used for reading. * * @return the lock used for reading */ Lock readLock(); /** * Returns the lock used for writing. * * @return the lock used for writing */ Lock writeLock(); } 所以 ReentrantReadWriteLock 并非是真的一个“锁”,而是一个读锁和写锁的管理器,而真正实现锁功能的是 ReentrantReadWriteLock 的静态内部类 ReadLock 和 WriteLock。ReadLock 和 WriteLock 都是直接实现 interface Lock。 当多线程共享同一个数据源时,为了避免数据上的错乱,我们需要在读数据的时候防止写入操作,在写入的时候也不能进行读操作。怎么实现这一业务?synchronized、ReentrantLock 都可以实现,在读、写操作的方法都加上锁的保护,则可实现读写互斥。但这种做法会使并发大大折扣,例如在某一时间段只有大量读操作并没有写操作,但此时读操作也要进行排队,此时 ReentrantReadWriteLock 的价值就能发挥得淋漓尽致。 ReentrantReadWriteLock 的作用:支持同时多读,读的时候不能写,写的时候不能读。 看看具体的 DEMO1,一个支持多用户的银行账号(夫妻共用)的存款和查询的需求: 1,可多用户同时查询余额(读操作) 2,当有用户在查询余额时(读操作),该账号不能进行存取款操作(写入操作) 3,当有用户在存取款时(写入操作),该账号不能进行查询余额操作(读操作) 具体实现: public class Test { static class User { int mID; BankAccount mBankAccount; public User(int ID, BankAccount bankAccount) { mID = ID; mBankAccount = bankAccount; } public void saveMoney(final int cash) { new Thread(new Runnable() { @Override public void run() { mBankAccount.saveMoney(mID, cash); } }).start(); } public void checkBalance() { new Thread(new Runnable() { @Override public void run() { mBankAccount.checkBalance(mID); } }).start(); } } /** * 支持多用户的银行账号(夫妻共用) */ static class BankAccount { int mBalance; ReentrantReadWriteLock mReentrantReadWriteLock = new ReentrantReadWriteLock(); ReentrantReadWriteLock.WriteLock mWriteLock = mReentrantReadWriteLock.writeLock(); ReentrantReadWriteLock.ReadLock mReadLock = mReentrantReadWriteLock.readLock(); public void saveMoney(int id, int cash) { mWriteLock.lock(); try { mBalance = mBalance + cash; System.out.println(" 用户 " + id + " 正在进行存钱操作 "); Thread.sleep(2000); System.out.println(" 用户 " + id + " 存钱完成,存入 " + cash + " 元 "); } catch (Exception e) { e.printStackTrace(); } finally { mWriteLock.unlock(); } } public void checkBalance(int id) { mReadLock.lock(); try { System.out.println(" 用户 " + id + " 正在进行查询余额操作 "); Thread.sleep(2000); System.out.println(" 余额:" + mBalance); } catch (Exception e) { e.printStackTrace(); } finally { mReadLock.unlock(); } } } public static void main(String[] var0) { BankAccount bankAccount = new BankAccount(); User user1 = new User(1, bankAccount); User user2 = new User(2, bankAccount); user1.saveMoney(1000000); // 同时查询余额 user1.checkBalance(); user2.checkBalance(); // 同时存款 user1.saveMoney(2000000); user2.saveMoney(6000); user1.checkBalance(); } } DEMO1 的输出: 用户 1 正在进行存钱操作 用户 1 存钱完成,存入 1000000 元 用户 1 正在进行查询余额操作 用户 2 正在进行查询余额操作 余额:1000000 余额:1000000 用户 1 正在进行存钱操作 用户 1 存钱完成,存入 2000000 元 用户 2 正在进行存钱操作 用户 2 存钱完成,存入 6000 元 用户 1 正在进行查询余额操作 余额:3006000 当两个用户同时查询余额时,可同时进行。 当两个用户同时存款时,不能同时进行,要进行队列排队。 可见,我们可以用 ReentrantReadWriteLock 进行一些读写需要互斥的一些业务上,特别适合在“大量读小量写”的业务,可以增大吞吐率。