重温java知识(三十九、JUC并发编程之五:线程锁之StampedLock【无障碍锁】)

读/写锁可以保证并发访问下的数据写入安全与读取性能,但是在读线程非常多的情况下,有可能造成写线程的长时间阻塞,从而减少写线程的调度次数。为此JUC中针对读/写锁提出了改进方案,提供了无障碍锁(StampedLock),使用这种锁的特点在于:若干个读线程彼此之间不会互相影响,但是依然可以保证多个写线程的独占操作。

在StampedLock中分为:

  • 乐观读
    3种模式,以提高并发处理性能,同时也可以实现锁类型的转换。

1、使用StampedLock实现银行账户并发操作的例子:

package com.mydemo;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.StampedLock;

public class JUCDemo {

    public static void main(String[] args) {

        // 实例化对象-存放数据
        Account account = new Account("张三", 0.0);

        double moneyData[] = new double[]{100.00, 200.00, 300.00, 400.00, 500.00};

        // 5个写入线程
        for(int i = 0; i < 5; i++){
            new Thread(
                    ()->{
                        for(int j = 0; j < moneyData.length; j++){
                            // 存放数据
                            account.saveMoney(moneyData[j]);
                        }
                    }, "写线程:"
            ).start();
        }

        // 30个读取线程
        for(int j = 0; j < 30; j++){
            new Thread(
                    ()->{
                        while (true){
                            // 获取数据
                            System.out.println(account.toString());
                        }
                    }, "读线程:"
            ).start();
        }
    }
}

// 银行账户
class Account{
    private String name;        // 账户名称
    private double asset;       // 账户资产

    // 读/写锁
    private StampedLock stampedLock = new StampedLock();

    /**
     * 双参构造函数---设置账户信息
     * @param name
     * @param asset
     */
    public Account(String name, double asset) {
        this.name = name;
        this.asset = asset;
    }

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

        try {
            // 转为写锁
            long writeStamp = this.stampedLock.tryConvertToWriteLock(stamp);
            while(flag){
                // 当前为写锁
                if(writeStamp != 0){
                    stamp = writeStamp;                     // 修改为写锁的标记
                    this.asset += money;                    // 进行资产修改
                    TimeUnit.SECONDS.sleep(1);    // 模拟延迟
                    System.out.println("【" + Thread.currentThread().getName() +
                            "】修改银行资产数据,修改金额:" + money +
                            ",当前资产:" + this.asset);

                    // 结束循环
                    flag = false;
                }else{
                    // 释放读锁
                    this.stampedLock.unlock(stamp);
                    // 获取写锁
                    writeStamp = this.stampedLock.writeLock();
                    stamp = writeStamp;
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            // 解锁
            this.stampedLock.unlock(stamp);
        }
    }

    /**
     * 数据读取
     * @return
     */
    public String toString(){
        // 获取乐观锁
        long stamp = this.stampedLock.tryOptimisticRead();

        try {

            double current = this.asset;          // 获取当前的资产
            TimeUnit.SECONDS.sleep(1);  // 模拟延迟

            /**
             * validate()方法虽然可以检测,但是依然有可能出现异常,
             * 所以本出依据StampledLock类的源代码多追加了一个验证机制
             */
            if(!this.stampedLock.validate(stamp) || (stamp & (long)(Math.pow(2,7)-1)) == 0){
                long readStamp = this.stampedLock.readLock();
                current = this.asset;
                stamp = readStamp;
            }

            return "【账户信息:(" + Thread.currentThread().getName() +
                    ")】账户名称:" + this.name +
                    "、银行资产:" + this.asset;

        }catch (Exception e){
            return null;
        }finally {
            try {
                this.stampedLock.unlock(stamp);
            }catch (Exception e){}
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值