Java多线程并发编程 — 读写锁 Reentrant Read Write Lock

来源:互联网 发布:典型hadoop云计算 编辑:程序博客网 时间:2024/05/22 11:49

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 进行一些读写需要互斥的一些业务上,特别适合在“大量读小量写”的业务,可以增大吞吐率。

阅读全文
0 0
原创粉丝点击