您的位置:首页 > 编程语言 > Java开发

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

2017-06-26 14:35 453 查看

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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: