项目简介

May 31, 2025 · View on GitHub

lock 为 java 设计的渐进式分布式锁,开箱即用,纵享丝滑。

Maven Central Build Status Coverage Status

开源地址:https://github.com/houbb/lock

目的

  • 开箱即用,支持注解式和过程式调用

  • 支持可重入锁获取

  • 基于 mysql 的分布式锁

  • 基于 redis 的分布式锁

  • 内置支持多种 redis 的整合方式

  • 渐进式设计,可独立于 spring 使用

  • 整合 spring

  • 整合 spring-boot

变更日志

变更日志

快速开始

需要

jdk1.7+

maven 3.x+

基于 MAP 的分布式锁

maven 引入

<dependency>
    <groupId>com.github.houbb</groupId>
    <artifactId>lock-core</artifactId>
    <version>1.7.2</version>
</dependency>

入门例子

基于本地 MAP 的入门测试案例。

ILock lock = LockBs.newInstance();
String key = "ddd";
try {
    // 加锁
    boolean lockFlag = lock.tryLock(key);
    Assert.assertTrue(lockFlag);
} catch (Exception e) {
    throw new RuntimeException(e);
} finally {
    // 释放锁
    lock.unlock(key);
}

接口说明

接口方法文档

方法签名参数说明返回值说明版本标记
boolean tryLock(final ILockContext context)context: 锁操作上下文对象加锁成功返回 true,失败 falsesince 1.5.0
boolean tryLock(String key, TimeUnit timeUnit, long lockTime, long waitLockTime, boolean reentrant)key: 锁标识
timeUnit: 时间单位
lockTime: 锁持有时长
waitLockTime: 最大等待时长
reentrant: 是否允许重入
加锁成功返回 true,失败 falsesince 1.5.0
boolean tryLock(String key, TimeUnit timeUnit, long lockTime, long waitLockTime)key: 锁标识
timeUnit: 时间单位
lockTime: 锁持有时长
waitLockTime: 最大等待时长
(默认 reentrant=true)
加锁成功返回 true,失败 falsesince 0.0.1
boolean tryLock(String key, TimeUnit timeUnit, long lockTime)key: 锁标识
timeUnit: 时间单位
lockTime: 锁持有时长
(默认 waitLockTime=0 仅尝试一次)
加锁成功返回 true,失败 falsesince 0.0.1
boolean tryLock(String key, long lockTime)key: 锁标识
lockTime: 锁持有时长(秒)
(默认 timeUnit=SECONDS)
加锁成功返回 true,失败 falsesince 0.0.1
boolean tryLock(String key)key: 锁标识
(默认 lockTime=10秒)
加锁成功返回 true,失败 falsesince 0.0.1
boolean unlock(String key)key: 锁标识
注意: 释放锁不重试,所有 key 有过期时间
释放成功返回 true,失败 falsesince 0.0.1

tryLock 方法说明

提供了较多方法,只是为了使用更加便捷。

boolean tryLock(final ILockContext context); 中的入参,和参数一一对应,默认值也相同。

context 的引入,为了避免后续的配置项较多,方法会膨胀的问题。

ILockContext lockContext = LockContext.newInstance()
        .key(key)
        .lockTime(LockConst.DEFAULT_LOCK_TIME)
        .waitLockTime(LockConst.DEFAULT_WAIT_LOCK_TIME)
        .reentrant(LockConst.DEFAULT_REENTRANT)
        .timeUnit(LockConst.DEFAULT_TIME_UNIT);

boolean lockFlag = lock.tryLock(lockContext);

锁的一些特性

锁的可重入性

概念:可重入性(reentrancy)是指一个线程在拥有一个资源(通常是一个锁)的情况下,再次获取该资源时不会造成死锁。可重入性在多线程编程中非常重要,因为它可以避免因线程之间的相互依赖而导致的死锁。

可重入的例子

我们支持一个线程可以多次获取一个锁,默认是可重入的。

@Test
public void reTest() {
    ILock lock = LockBs.newInstance();
    String key = "ddd";
    try {
        // 加锁
        boolean lockFlag = lock.tryLock(key);
        //1. 首次获取锁成功
        Assert.assertTrue(lockFlag);
        //2. 重新获取锁成功
        boolean reLockFlag = lock.tryLock(key);
        Assert.assertTrue(reLockFlag);
    } catch (Exception e) {
        throw new RuntimeException(e);
    } finally {
        // 释放锁
        lock.unlock(key);
    }
}

不可重入的例子

当然,我们也支持不可重入的形式,指定对应的配置即可。

public void noReTest() {
    ILock lock = LockBs.newInstance();
    String key = "ddd";
    try {
        ILockContext lockContext = LockContext.newInstance()
                .key(key)
                .waitLockTime(5)
                .reentrant(false);  // 指定不可重入

        boolean lockFlag = lock.tryLock(lockContext);
        //1. 首次获取锁成功
        Assert.assertTrue(lockFlag);
        //2. 不是重入,第二次获取失败
        boolean reLockFlag = lock.tryLock(lockContext);
        Assert.assertFalse(reLockFlag);
    } catch (Exception e) {
        throw new RuntimeException(e);
    } finally {
        // 释放锁
        lock.unlock(key);
    }
}

不可重入锁,第二次获取就会失败。

配置化

为了便于拓展,LockBs 的配置支持自定义:

LockBs.newInstance()
        .id(Ids.uuid32())   //id 生成策略
        .cache(JedisRedisServiceFactory.pooled("127.0.0.1", 6379)) //缓存策略
        .lockSupport(new RedisLockSupport())    // 锁实现策略
        .lockKeyFormat(new LockKeyFormat())     // 针对 key 的格式化处理策略
        .lockReleaseFailHandler(new LockReleaseFailHandler())   //释放锁失败处理
        ;

可配置项如下:

属性配置说明

属性名类型默认值说明版本标记
idIdIds.uuid32()唯一标识生成策略since 0.0.4
cacheICommonCacheServicenew CommonCacheServiceMap()缓存实现策略since 0.0.4
lockSupportILockSupportnew CommonCacheLockSupport()锁底层支持策略since 1.0.0
lockKeyFormatILockKeyFormatnew LockKeyFormat()锁 Key 格式化处理器since 1.2.0
lockReleaseFailHandlerILockReleaseFailHandlernew LockReleaseFailHandler()锁释放失败处理策略since 1.2.0
tryLockIntervalMillsintLockConst.DEFAULT_TRY_LOCK_INTERVAL_MILLS尝试加锁的轮询间隔(毫秒)since 1.6.0

整合 spring

maven 引入

<dependency>
    <groupId>com.github.houbb</groupId>
    <artifactId>lock-spring</artifactId>
    <version>1.7.2</version>
</dependency>

指定 bean 使用

启用分布式锁

@EnableLock 启用分布式锁。

@EnableRedisConfig 启用 redis 的默认配置。

@Configurable
@ComponentScan(basePackages = "com.github.houbb.lock.test.service")
@EnableLock
@EnableRedisConfig
public class SpringConfig {
}

EnableLock 注解说明,和引导类对应:

@EnableLock 注解属性说明

属性名描述默认值
id()唯一标识生成策略"lockId"
cache()缓存实现策略的 Bean 名称"springRedisService"
lockKeyFormat()加锁 Key 格式化策略"lockKeyFormat"
lockKeyNamespace()锁 Key 的默认命名空间LockConst.DEFAULT_LOCK_KEY_NAMESPACE
lockReleaseFailHandler()锁释放失败处理类"lockReleaseFailHandler"

其中 springRedisService 使用的是 redis-config 中的实现。

对应注解 @EnableRedisConfig,redis 的配置信息如下:

配置说明默认值
redis.addressredis 地址127.0.0.1
redis.portredis 端口6379
redis.passwordredis 密码

当然,你可以使用自己想用的其他缓存实现,只需要实现对应的接口标准即可。

使用 LockBs

我们可以直接 LockBs 的引导类,这种适合一些更加灵活的场景。

@ContextConfiguration(classes = SpringConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringServiceRawTest {

    @Autowired
    private UserService userService;

    @Autowired
    private LockBs lockBs;

    @Test
    public void queryLogTest() {
        final String key = "name";
        try {
            boolean lockFlag = lockBs.tryLock(key);
            final String value = userService.rawUserName(1L);
        } catch (Exception exception) {
            throw new RuntimeException(exception);
        } finally {
            lockBs.unlock(key);
        }
    }

}

aop 注解使用

指定方法注解

当然,我们可以在方法上直接指定注解 @Lock,使用更加方便。

直接使用,AOP 切面生效即可。

@Service
public class UserService {

    @Lock
    public String queryUserName(Long userId) {
    }

    @Lock(value = "#user.name")
    public void queryUserName2(User user) {
    }
}

@Lock 属性说明,value 用于指定 key,支持 SPEL 表达式。

如果 aop 中拦截获取锁失败,默认会抛出异常。

其他属性,和引导类的方法参数一一对应。

@Lock 注解属性说明

属性名类型默认值说明
value()String""锁的 Key 策略(支持 SpEL 表达式)
例:@Lock("order:#{#orderId}")
timeUnit()TimeUnitTimeUnit.SECONDS时间单位(秒/毫秒等)
waitLockTime()longLockConst.DEFAULT_WAIT_LOCK_TIME等待锁的最长时间
通常为 0(仅尝试一次)或正数(持续重试)
lockTime()longLockConst.DEFAULT_LOCK_TIME锁持有时间
通常为 10-30 秒(防止死锁)
reentrant()booleanLockConst.DEFAULT_REENTRANT是否允许重入
通常为 true(同一线程可重复获取)

spring boot 整合

maven 引入

<dependency>
    <groupId>com.github.houbb</groupId>
    <artifactId>lock-springboot-starter</artifactId>
    <version>1.7.2</version>
</dependency>

使用

所有的配置会自动生效。

使用方式同 spring。

后期 Road-MAP

  • 支持锁的可重入

持有锁的线程可以多次获取锁

  • 分布式锁注解支持

  • spring 的锁支持拓展性扩展,而不是局限于 redis-lock

  • watch-dog,添加锁的自动续租?

拓展阅读

Redis 分布式锁

java 从零实现 redis 分布式锁

开源矩阵

下面是一些缓存系列的开源矩阵规划。

名称介绍状态
resubmit防止重复提交核心库已开源
rate-limit限流核心库已开源
cache手写渐进式 redis已开源
lock开箱即用的分布式锁已开源
common-cache通用缓存标准定义已开源
redis-config兼容各种常见的 redis 配置模式已开源
quota-server限额限次核心服务待开始
quota-admin限额限次控台待开始
flow-control-server流控核心服务待开始
flow-control-admin流控控台待开始