添加Redis分布式锁

本文介绍了如何使用Redisson客户端在Java中实现分布式锁,确保加锁和设置过期时间的原子性,避免因程序中断导致锁无法释放的问题。同时,通过Lua脚本确保删除锁的操作也是原子性的。此外,展示了在项目重启时如何通过初始化组件自动清除Redis中的锁,以保持系统的正常运行。
摘要由CSDN通过智能技术生成
  1. 加锁+过期时间必须是一个原子性操作,如果锁已经加上了,在设置过期时间时程序断电,则会导致锁一直存在,利用setIfAbsent的Api中的加锁+过期时间解决该问题
  2. 删除锁也要是个原子操作,先查再删依然会出现以上情况,利用redis执行lua脚本解决删除锁问题

pom

        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.10.6</version>
        </dependency>

加锁

 	@Autowired
    private OldMarketDataService oldMarketDataService;

    @Autowired
    private RedissonClient redissonClient;

    @Resource
    private MsHistoryCodeMapper msHistoryCodeMapper;

    public static final String MS_HISTORY = "MS_HISTORY";

    public static final ThreadPoolExecutor POOL = new ThreadPoolExecutor(
            1,
            1,
            60,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(1),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.DiscardPolicy()
    );

    @Override
    public void syncOld() {
        POOL.execute(() -> {
            RLock lock = redissonClient.getLock(MS_HISTORY);
            try {
                boolean isLock = lock.tryLock(10, TimeUnit.MINUTES);
                if (isLock) {
                    msHistoryCodeMapper.updateDealStatus1();
                    List<MsHistoryCodePO> msHistoryCodePoList = msHistoryCodeMapper.queryListByStatus1();
                    if (CollectionUtils.isEmpty(msHistoryCodePoList)) {
                        return;
                    }
                    msHistoryCodePoList.forEach(msHistoryCodePo -> {
                        oldMarketDataService.syncOldByMarket(msHistoryCodePo.getMarketId());
                        msHistoryCodeMapper.updateStatusById(msHistoryCodePo.getId(), 2);
                    });
                }

            } catch (Exception e) {
                log.error("异常日志", e);
            } finally {
                if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }
        });
    }

redis配置类

/**
 * redis配置
 *
 * @author XLJ
 * @date 2020/12/28 16:24
 */
@Configuration
public class RedisConfig {

    @Value("${spring.redis.cluster.nodes}")
    private String nodes;
    @Value("${spring.redis.password}")
    private String password;

    @Bean
    public RedissonClient redissonClient() {
        if (StringUtils.isBlank(nodes)) {
            throw new RuntimeException("nodes can not be empty!");
        }
        String address = "redis://%s";
        String[] split = nodes.split(",");
        String[] array = new String[split.length];
        for (int i = 0; i < split.length; i++) {
            String format = String.format(address, split[i]);
            array[i] = format;
        }

        Config config = new Config();
        config.useClusterServers().addNodeAddress(array).setPassword(password);

        return Redisson.create(config);
    }
}

项目重启清除锁

/**
 * 项目重启后清除redis锁
 *
 * @author xlj
 * @date 2021/1/12
 */
@Component
@Slf4j
public class RedisInit implements ApplicationContextAware {

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        RedissonClient bean = applicationContext.getBean(RedissonClient.class);
        bean.getKeys().delete(MrkHistoryScheduleTaskServiceImpl.MS_HISTORY);
        log.info("清除Redis中的主站行情历史数据锁 --> {}", MrkHistoryScheduleTaskServiceImpl.MS_HISTORY);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序少年不秃头

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值