多线程之StampedLock并发操作

ReentrantReadWriteLock读/写锁可以保证并发访问下的数据写入安全和读取性能,但是在读线程非常多的情况下.有可能造成写线程的长时间阻塞.从而减少写线程的调用次数.为此JUC中针对读/写锁提出了改进方案.提供了无障碍锁StampedLock,使用这种锁的特点在于:若干读线程彼此间不会相互影响.但是依然可以保证多个写线程的独占操作.
StampedlLock中分为3中模式.写.读,乐观锁.以提高并发处理性能.同时也可以 实现类型转换

public class Account {
    //账号名称
    private String name;
    //资产
    private double asset;
    //读写锁
//    private ReadWriteLock lock=new ReentrantReadWriteLock();
    private StampedLock lock = new StampedLock();

    public Account(String name, double asset) {
        this.name = name;
        this.asset = asset;
    }

    /**
     * 资产追加
     *
     * @param money
     */
    public void saveMoney(double money) {
        //获取读锁.检查状态
        long stamp = this.lock.readLock();
        boolean flag = true;

        try {
            //转化为写锁
            long writeStamp = this.lock.tryConvertToWriteLock(stamp);
            while (flag) {
                if (writeStamp != 0) {
                    stamp = writeStamp;
                    this.asset += money;
                    System.out.println(Thread.currentThread().getName() + "修改银行账户数据:" + money + ";当前资产:" + this.asset);
                    flag = false;
                } else {
                    //没有获取到写锁
                    //释放读锁
                    this.lock.unlockRead(stamp);
                    //获取写锁
                    stamp = this.lock.writeLock();
                }
            }
        } catch (Exception e) {
        } finally {
            this.lock.unlock(stamp);
        }

    }

    /**
     * 获取资产数据
     *
     * @return
     */
    public String getAsset() {
        //获取读锁
        long stamp = this.lock.tryOptimisticRead();
        try {
            double current = this.asset;
            //validate()方法虽然可以检查但是依然有可能出现异常.所以本处依据StampledLock类的源码多追加了一个验证机制
            if (!this.lock.validate(stamp) || (stamp & (long) (Math.pow(2, 7) - 1)) == 0) {
                long readStamp = this.lock.readLock();
                current = this.asset;
                stamp = readStamp;
            }
            return "账户信息:" + Thread.currentThread().getName() + ";账户名称:" + this.name + ";总资产:" + asset;
        } catch (Exception e) {
            return null;
        } finally {
            //释放指定的写锁
            try {
                this.lock.unlockRead(stamp);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }.
public class JUCDemo2 {
    public static void main(String[] args) {
        Account accout = new Account("QYF", 0.0);
        double[] moneys = new double[]{120.0, 100.0, 80.0, 60.0, 40.0, 10.0, 5.0};

        //写线程存放资产
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                for (int n = 0; n < moneys.length; n++) {
                    accout.saveMoney(moneys[n]);
                }
            }).start();
        }

        //读线程读取数据
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                System.err.println(accout.getAsset());
            }).start();
        }
    }
}

输出结果:

Thread-0修改银行账户数据:120.0;当前资产:120.0
Thread-0修改银行账户数据:100.0;当前资产:220.0
Thread-0修改银行账户数据:80.0;当前资产:300.0
Thread-0修改银行账户数据:60.0;当前资产:360.0
Thread-0修改银行账户数据:40.0;当前资产:400.0
Thread-0修改银行账户数据:10.0;当前资产:410.0
Thread-0修改银行账户数据:5.0;当前资产:415.0
Thread-1修改银行账户数据:120.0;当前资产:535.0
Thread-1修改银行账户数据:100.0;当前资产:635.0
Thread-1修改银行账户数据:80.0;当前资产:715.0
Thread-1修改银行账户数据:60.0;当前资产:775.0
Thread-1修改银行账户数据:40.0;当前资产:815.0
Thread-1修改银行账户数据:10.0;当前资产:825.0
Thread-1修改银行账户数据:5.0;当前资产:830.0
Thread-2修改银行账户数据:100.0;当前资产:930.0
Thread-2修改银行账户数据:80.0;当前资产:1010.0
Thread-2修改银行账户数据:60.0;当前资产:1070.0
Thread-2修改银行账户数据:40.0;当前资产:1110.0
Thread-2修改银行账户数据:10.0;当前资产:1120.0
Thread-2修改银行账户数据:5.0;当前资产:1125.0
账户信息:Thread-10;账户名称:QYF;总资产:830.0
账户信息:Thread-6;账户名称:QYF;总资产:830.0
账户信息:Thread-5;账户名称:QYF;总资产:830.0
账户信息:Thread-3;账户名称:QYF;总资产:830.0
账户信息:Thread-9;账户名称:QYF;总资产:830.0
账户信息:Thread-12;账户名称:QYF;总资产:1125.0
账户信息:Thread-7;账户名称:QYF;总资产:1125.0
账户信息:Thread-4;账户名称:QYF;总资产:1125.0
账户信息:Thread-11;账户名称:QYF;总资产:1125.0
账户信息:Thread-8;账户名称:QYF;总资产:1125.0

在Account类中利用StampedLock类获取读锁和写锁.为防止过多读取所造成的的写线程阻塞,所以在进行写入前都会首先判断读锁的状态.并利用转换方法实现了读锁与写锁的转换.这样就解决了读/写锁的缺陷.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值