当前位置: 首页>后端>正文

自研分布式锁组件

package com.xx.xxx.common.distributedLock;

import org.jetbrains.annotations.NotNull;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.redis.core.StringRedisTemplate;

import org.springframework.data.redis.core.script.DefaultRedisScript;

import java.util.Arrays;

import java.util.Timer;

import java.util.TimerTask;

import java.util.concurrent.TimeUnit;

import java.util.concurrent.locks.Condition;

import java.util.concurrent.locks.Lock;

/**

* @author?

* @ClassName: RedisDistributedLock

* @Description:

* @date 2023/12/14 11:10

*/

public class RedisDistributedLockimplements Lock {

private StringRedisTemplatestringRedisTemplate;

? ? private StringlockName;//KEYS[1]

? ? private Stringuuid;//ARGV[1]

? ? private long timeout;//ARGV[2]

? ? @Autowired

? ? public RedisDistributedLock(StringRedisTemplate stringRedisTemplate, String lockName, String uuid){

this.stringRedisTemplate = stringRedisTemplate;

? ? ? ? this.lockName = lockName;

? ? ? ? this.uuid = uuid + Thread.currentThread().getId();

? ? ? ? this.timeout =30L;

? ? }

@Override

? ? public void lock() {

tryLock();

? ? }

@Override

? ? public void lockInterruptibly()throws InterruptedException {

}

@Override

? ? public boolean tryLock() {

try {

tryLock(-1L, TimeUnit.SECONDS);

? ? ? ? }catch (InterruptedException e) {

throw new RuntimeException(e);

? ? ? ? }

return false;

? ? }

@Override

? ? public boolean tryLock(long time, @NotNull TimeUnit unit)throws InterruptedException {

if(-1 == time){

String script ="if redis.call('exists', KEYS[1]) == 0 or redis.call('hexists', KEYS[1], ARGV[1]) == 1 then " +

"redis.call('hincrby', KEYS[1], ARGV[1], 1) " +

"redis.call('expire', KEYS[1], ARGV[2]) " +

"return 1 " +

"else " +

"return 0 " +

"end";

? ? ? ? ? ? //加锁

? ? ? ? ? ? while (Boolean.FALSE.equals(stringRedisTemplate.execute(new DefaultRedisScript<>(script, Boolean.class), Arrays.asList(lockName), this.uuid, String.valueOf(this.timeout)))){

try{

TimeUnit.SECONDS.sleep(60L);

? ? ? ? ? ? ? ? }catch (InterruptedException e){

e.printStackTrace();

? ? ? ? ? ? ? ? }

}

// 加锁成功之后,新建一个后台扫描程序

? ? ? ? ? ? resetExpire();

? ? ? ? ? ? System.out.println("lockName:" +lockName +"\t" +"uuid:" +uuid);

return true;

? ? ? ? }

return false;

? ? }

@Override

? ? public void unlock() {

String script ="" +

"if redis.call('hexists', KEYS[1], ARGV[1]) == 0 then " +

"return nil " +

"elseif redis.call('hincrby', KEYS[1], ARGV[1], -1) == 0 then " +

"return redis.call('del', KEYS[1]) " +

"else " +

"return 0 " +

"end";

? ? ? ? System.out.println("unlock lockName:" +lockName +"\t" +"uuid:" +uuid);

? ? ? ? Long flag =stringRedisTemplate.execute(new DefaultRedisScript<>(script, Long.class),

? ? ? ? ? ? ? ? Arrays.asList(lockName), uuid);

? ? ? ? if(null == flag) {

throw new RuntimeException("this lock does not exists");

? ? ? ? }

}

@NotNull

@Override

? ? public ConditionnewCondition() {

return null;

? ? }

//自动续期

? ? private void resetExpire() {

String script ="if redis.call('hexists', KEYS[1], ARGV[1]) == 1 then " +

"return redis.call('expire', KEYS[1], ARGV[2])" +

"else " +

"return 0 " +

"end";

? ? ? ? new Timer().schedule(new TimerTask() {

@Override

? ? ? ? ? ? public void run() {

if(stringRedisTemplate.execute(

new DefaultRedisScript<>(script, Boolean.class),

? ? ? ? ? ? ? ? ? ? ? ? Arrays.asList(lockName),

? ? ? ? ? ? ? ? ? ? ? ? uuid,

? ? ? ? ? ? ? ? ? ? ? ? String.valueOf(timeout)

)){

System.out.println("resetExpire lockName:" +lockName +"uuid:" +uuid);

? ? ? ? ? ? ? ? }

}

}, this.timeout/3, 100);

? ? }

}

package com.xx.xx.common.distributedLock;

import cn.hutool.core.util.IdUtil;

import lombok.AllArgsConstructor;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.redis.core.StringRedisTemplate;

import org.springframework.stereotype.Component;

import java.util.concurrent.locks.Lock;

/**

* @author xx

* @ClassName: DistributedLockFactory

* @Description:

* @date 2023/12/14 14:42

*/

@Component

public class DistributedLockFactory {

private StringRedisTemplatestringRedisTemplate;

? ? private Stringuuid;

? ? public DistributedLockFactory(StringRedisTemplate stringRedisTemplate) {

this.stringRedisTemplate = stringRedisTemplate;

? ? ? ? this.uuid = IdUtil.simpleUUID();

? ? }

public LockgetDistributedLock(String lockType, String lockName) {

if(lockType ==null){

return null;

? ? ? ? }

if("REDIS".equalsIgnoreCase(lockType)){

return new RedisDistributedLock(stringRedisTemplate, lockName, uuid);

? ? ? ? }else if ("ZK".equalsIgnoreCase(lockType)){

}

return null;

? ? }

}

package com.xxx.xxx.customer.service.impl;

import cn.hutool.core.util.IdUtil;

import com.xxx.xxx.common.distributedLock.DistributedLockFactory;

import com.xxx.xxx.common.distributedLock.RedisDistributedLock;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.redis.core.StringRedisTemplate;

import org.springframework.stereotype.Service;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

/**

* @author xxx

* @ClassName: InventoryService

* @Description:

* @date 2023/12/13 16:28

*/

@Service

public class InventoryService {

private final StringRedisTemplatestringRedisTemplate;

? ? private DistributedLockFactorydistributedLockFactory;

? ? private Locklock =new ReentrantLock();

? ? public InventoryService(StringRedisTemplate stringRedisTemplate, DistributedLockFactory distributedLockFactory) {

this.stringRedisTemplate = stringRedisTemplate;

? ? ? ? this.distributedLockFactory = distributedLockFactory;

? ? }

public Stringsale(){

System.out.println("InventoryService:" +stringRedisTemplate);

//? ? ? ? Lock redisDistributedLock = new RedisDistributedLock(stringRedisTemplate, "luojiaRedisLock");

? ? ? ? Lock redisDistributedLock =distributedLockFactory.getDistributedLock("REDIS", "luojiaRedisLock");

? ? ? ? String resMessage ="";

? ? ? ? redisDistributedLock.lock();

? ? ? ? try {

// 1查询库存

? ? ? ? ? ? String result =stringRedisTemplate.opsForValue().get("stock");

? ? ? ? ? ? Thread.sleep(35000);

? ? ? ? ? ? // 2 判断库存是否足够

? ? ? ? ? ? Integer inventoryNum = result ==null ?0 : Integer.parseInt(result);

? ? ? ? ? ? // 3 扣减库存,每次减少一个

? ? ? ? ? ? if(inventoryNum >0){

stringRedisTemplate.opsForValue().set("stock", String.valueOf(--inventoryNum));

//? ? ? ? ? ? ? ? testEntryRetry();

? ? ? ? ? ? }else {

System.out.println("sold out");

? ? ? ? ? ? }

}catch (InterruptedException e) {

throw new RuntimeException(e);

? ? ? ? }finally {

redisDistributedLock.unlock();

? ? ? ? }

return resMessage;

? ? }

private void testEntryRetry(){

Lock redisLock =distributedLockFactory.getDistributedLock("REDIS", "luojiaRedisLock");

? ? ? ? redisLock.lock();

? ? ? ? try {

System.out.println("测试可重入锁");

? ? ? ? }finally {

redisLock.unlock();

? ? ? ? }

}

}


https://www.xamrdz.com/backend/3uw1920687.html

相关文章: