java读写锁


工作遇到了金钱计算,需要用到读写锁保证数据安全。记录一下。

单纯读没有限制,读写、写写的时候会有安全问题。

hashMap存在并发线程安全问题,而hashtable线程安全但每次修改的时候使用synchronized锁住整个表效率很低。推荐使用ConcurrentHashMapConcurrentHashMap只是保证了put()、get()操作是线程安全。并发问题依然存在。使用putIfAbsent()方法保证线程安全。因为putIfAbsent()自带锁。putIfAbsent()同时只有一个线程可以进行判断,其余线程循环等待判断。

static ConcurrentHashMap  paycertifyMap=new ConcurrentHashMap<>();

使用map存储流水号和读写锁对象,需要使用的时候 根据从map查询出锁对象然后 tryLock() 只会尝试一次获取锁对象,成功获取返回true。而 lock() 获取不到锁时休眠等待获取为止。然后常规使用 即可。

--由于本项目在controller层就使用了多线程 service不需要多线程。

ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

//先去map查询是否存在该流水号的写锁对象
if (paycertifyMap.putIfAbsent(bizMnPaycertifyVO.getHkls(), lock) != null) {
        //map已存在数据,赋值
        lock = paycertifyMap.putIfAbsent(bizMnPaycertifyVO.getHkls(), lock);
    }
    //等于null 添加成功 锁对象为新增的lock
    if (!lock.writeLock().tryLock()) {
        //获取锁失败
        return -1;
    }
    //获取锁成功
    try {
        //测试并发
        Thread.sleep(5000);
        //逻辑方法
        paycertifyAddUpdate(bizMnPaycertifyVO);
    } catch (Exception e) {
        logger.error("新增/修改支付凭证异常" + e);
    } finally {
        //释放锁 
        //一般释放锁需要判断是否由该线程获取的锁,避免释放其他线程锁,但是这里使用了ConcurrentHashMap保证了同一时间只存在一个线程持有该锁
        lock.writeLock().unlock();
        
    }
    return 0;