前言:或许经常会听到分布式集群情况下,JVM锁会失效。那么为什么分布式情况下synchronized会失效呢?
一、那么首先我们需要弄清楚什么是线程锁,什么是进程锁,什么分布式锁。
线程锁:主要是用来给方法,代码块加锁。对同一时刻仅有同一线程执行改方法或代码块。线程锁只在同一JVM有效果,因为线程的实现在根本上是依靠线程之间共享内存实现的,比如synchronized实在共享对象头,显示锁Lock是共享某个变量
进程锁,为了控制同一操作系统多个进程访问某个共享资源,划重点(因为每个进程具有独立性,各个进程无法访问其他进程资源,因此synchronized失效。)
分布式锁:当多个进程在不同的系统中,用分布式锁控制多个进程对资源访问。
二、使用场景:
多JVM情况下才会采用,一般单体架构,一个jvm是完全没必要采用分布式锁,这样很耗资源
三、分布式锁的实现(Redis)
1,代码
/** * 锁库 */ suspend fun lockStock(apiMdStockLockParam: ApiMdStockLockParam) { if (RedissLockUtil.tryLock(SystemConst.STOCK_LOCK_KEY,20,23)){ try { doMapperTra (SystemConst.account){ MdOtherUserService.checkOtherUser(apiMdStockLockParam.otherName,apiMdStockLockParam.otherPassword,this) apiMdStockLockParam.list.forEach {param -> val mdStock = oGetMapper<MdStockMapper>().selectOne { eq(MdStock::inventoryId,param.inventoryId) eq(MdStock::delFlag,0) }.oNl("即时库存id不存在") if (mdStock.availableQty!!.compareTo(param.number) ==-1) throw RuntimeException("库存不足") if (param.number.compareTo(BigDecimal.ZERO)<1) throw RuntimeException("锁库数量应大于0") oGetMapper<MdStockMapper>().updateBy( MdStock( baseLockQty = mdStock.baseLockQty!!.add(param.number), availableQty = mdStock.availableQty!!.subtract(param.number) )){ eq(MdStock::mdStockId,mdStock.mdStockId) } } } }finally { RedissLockUtil.unlock(SystemConst.STOCK_LOCK_KEY) } }else{ throw RuntimeException("锁库等待超时") } }
2.工具类:
package com.cloudinward.ynmd.config.redisson import org.redisson.api.RLock import org.redisson.api.RedissonClient import org.slf4j.LoggerFactory import java.util.concurrent.TimeUnit object RedissLockUtil { private val log = LoggerFactory.getLogger(RedissLockUtil::class.java) private var redissonClient: RedissonClient = redisson /** * 加锁 * @param lockKey * @return */ fun lock(lockKey: String): RLock { val lock = redissonClient.getLock(lockKey) lock.lock() return lock } /** * 释放锁 * @param lockKey */ fun unlock(lockKey: String) { try { val lock = redissonClient.getLock(lockKey) lock.unlock() } catch (e: Exception) { log.error("释放锁:$lockKey 错误", e) } } /** * 释放锁 * @param lock */ fun unlock(lock: RLock) { lock.unlock() } /** * 带超时的锁 * @param lockKey * @param timeout 超时时间 单位:秒 */ fun lock(lockKey: String, timeout: Int): RLock { val lock = redissonClient.getLock(lockKey) lock.lock(timeout.toLong(), TimeUnit.SECONDS) return lock } /** * 带超时的锁 * @param lockKey * @param unit 时间单位 * @param timeout 超时时间 */ fun lock(lockKey: String, unit: TimeUnit, timeout: Int): RLock { val lock = redissonClient.getLock(lockKey) lock.lock(timeout.toLong(), unit) return lock } /** * 尝试获取锁 * @param lockKey 时间单位秒 * @param waitTime 最多等待时间 * @param leaseTime 上锁后自动释放锁时间 * @return */ fun tryLock(lockKey: String, waitTime: Int, leaseTime: Int): Boolean { val lock = redissonClient.getLock(lockKey) try { return lock.tryLock(waitTime.toLong(), leaseTime.toLong(), TimeUnit.SECONDS) } catch (e: InterruptedException) { return false } } /** * 尝试获取锁 * @param lockKey * @param unit 时间单位 * @param waitTime 最多等待时间 * @param leaseTime 上锁后自动释放锁时间 * @return */ fun tryLock(lockKey: String, unit: TimeUnit, waitTime: Int, leaseTime: Int): Boolean { val lock = redissonClient.getLock(lockKey) try { return lock.tryLock(waitTime.toLong(), leaseTime.toLong(), unit) } catch (e: InterruptedException) { return false } } }