Java分布式锁案例

wen java案例 1

本文目录导读:

Java分布式锁案例

  1. 基于Redis的分布式锁
  2. 基于ZooKeeper的分布式锁
  3. 使用Spring Integration分布式锁
  4. 分布式锁实战应用示例
  5. 分布式锁配置类
  6. Maven依赖配置
  7. 关键设计要点

我来为您提供Java分布式锁的完整案例,包含多种实现方案:

基于Redis的分布式锁

1 基础版本 - 使用SETNX + 过期时间

import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
public class RedisLock {
    private Jedis jedis;
    private String lockKey;
    private String lockValue;
    private long expireTime = 30; // 默认过期时间(秒)
    public RedisLock(Jedis jedis, String lockKey) {
        this.jedis = jedis;
        this.lockKey = lockKey;
    }
    /**
     * 获取分布式锁
     */
    public boolean lock(long waitTimeout, long expireTime) {
        this.lockValue = UUID.randomUUID().toString();
        this.expireTime = expireTime;
        long startTime = System.currentTimeMillis();
        try {
            // 使用SET命令实现原子性加锁
            while (true) {
                SetParams params = new SetParams();
                params.nx().px(expireTime * 1000);
                String result = jedis.set(lockKey, lockValue, params);
                if ("OK".equals(result)) {
                    System.out.println("获取锁成功: " + lockValue);
                    return true;
                }
                // 判断是否超时
                if ((System.currentTimeMillis() - startTime) > waitTimeout) {
                    System.out.println("获取锁超时");
                    return false;
                }
                Thread.sleep(100); // 等待100ms后重试
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 释放分布式锁(使用Lua脚本保证原子性)
     */
    public void unlock() {
        String script = "if redis.call('get',KEYS[1]) == ARGV[1] then " +
                       "return redis.call('del',KEYS[1]) " +
                       "else return 0 end";
        Long result = (Long) jedis.eval(script, 
                       java.util.Collections.singletonList(lockKey), 
                       java.util.Collections.singletonList(lockValue));
        if (result > 0) {
            System.out.println("释放锁成功: " + lockValue);
        } else {
            System.out.println("释放锁失败,锁已过期或被其他线程持有");
        }
    }
    // 使用示例
    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost", 6379);
        RedisLock lock = new RedisLock(jedis, "product:1001");
        try {
            // 尝试获取锁,等待5秒,锁过期时间30秒
            if (lock.lock(5000, 30)) {
                // 执行业务逻辑
                System.out.println("执行业务逻辑...");
                Thread.sleep(2000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

2 使用Redisson框架(推荐)

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import java.util.concurrent.TimeUnit;
public class RedissonLockDemo {
    private RedissonClient redissonClient;
    public void init() {
        Config config = new Config();
        config.useSingleServer()
              .setAddress("redis://localhost:6379")
              .setPassword("123456")
              .setConnectionPoolSize(10)
              .setConnectionMinimumIdleSize(5);
        redissonClient = Redisson.create(config);
    }
    /**
     * 使用Redisson分布式锁(自动续期机制)
     */
    public void demoLock() {
        RLock lock = redissonClient.getLock("order:lock");
        try {
            // 尝试加锁,等待2秒,持锁30秒
            if (lock.tryLock(2, 30, TimeUnit.SECONDS)) {
                System.out.println("获取锁成功");
                // 执行业务逻辑
                businessProcess();
            } else {
                System.out.println("获取锁失败");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
                System.out.println("释放锁");
            }
        }
    }
    // 看门狗机制 - 自动续期
    public void demoWithWatchDog() {
        RLock lock = redissonClient.getLock("order:lock");
        try {
            // 不指定过期时间,使用看门狗自动续期(默认30秒,每10秒续期一次)
            lock.lock();
            System.out.println("获取锁成功,自动续期模式");
            // 长时间业务操作,不需要担心锁过期
            businessProcess();
        } finally {
            lock.unlock();
        }
    }
    private void businessProcess() {
        // 模拟业务逻辑
        try {
            Thread.sleep(5000);
            System.out.println("业务处理完成");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

基于ZooKeeper的分布式锁

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
public class ZookeeperLock implements Watcher {
    private ZooKeeper zk;
    private String root = "/locks";
    private String lockName;
    private String selfPath;
    private String waitPath;
    private CountDownLatch connectedLatch = new CountDownLatch(1);
    private CountDownLatch waitLatch;
    public ZookeeperLock(String connectString, String lockName) {
        this.lockName = lockName;
        try {
            zk = new ZooKeeper(connectString, 3000, this);
            connectedLatch.await();
            // 创建根节点
            if (zk.exists(root, false) == null) {
                zk.create(root, new byte[0], 
                    ZooDefs.Ids.OPEN_ACL_UNSAFE, 
                    CreateMode.PERSISTENT);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 尝试获取锁(临时顺序节点实现)
     */
    public boolean lock() {
        try {
            // 创建临时顺序节点
            selfPath = zk.create(root + "/" + lockName, 
                new byte[0], 
                ZooDefs.Ids.OPEN_ACL_UNSAFE, 
                CreateMode.EPHEMERAL_SEQUENTIAL);
            System.out.println("创建节点: " + selfPath);
            // 获取所有子节点
            List<String> children = zk.getChildren(root, false);
            Collections.sort(children);
            // 判断当前节点是否是最小节点
            String selfNode = selfPath.substring(selfPath.lastIndexOf("/") + 1);
            int index = children.indexOf(selfNode);
            if (index == 0) {
                // 最小节点,获取锁成功
                System.out.println("获取锁成功");
                return true;
            } else {
                // 监听前一个节点
                waitPath = root + "/" + children.get(index - 1);
                waitLatch = new CountDownLatch(1);
                zk.exists(waitPath, true);
                System.out.println("等待前一个节点释放: " + waitPath);
                // 等待前一个节点删除
                waitLatch.await();
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 释放锁
     */
    public void unlock() {
        try {
            if (zk != null && selfPath != null) {
                zk.delete(selfPath, -1);
                System.out.println("释放锁: " + selfPath);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (zk != null) {
                    zk.close();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    @Override
    public void process(WatchedEvent event) {
        if (event.getState() == Event.KeeperState.SyncConnected) {
            connectedLatch.countDown();
        }
        // 检查节点删除事件
        if (event.getType() == Event.EventType.NodeDeleted) {
            if (event.getPath().equals(waitPath)) {
                waitLatch.countDown();
            }
        }
    }
    // 使用示例
    public static void main(String[] args) {
        ZookeeperLock lock = new ZookeeperLock("localhost:2181", "order");
        try {
            if (lock.lock()) {
                System.out.println("执行业务逻辑...");
                Thread.sleep(3000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

使用Spring Integration分布式锁

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.redis.util.RedisLockRegistry;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
@Service
public class SpringIntegrationLockDemo {
    @Autowired
    private RedisLockRegistry redisLockRegistry;
    public void businessMethod(String orderId) {
        // 创建锁
        Lock lock = redisLockRegistry.obtain("lock:" + orderId);
        boolean isLocked = false;
        try {
            // 尝试获取锁,等待5秒
            isLocked = lock.tryLock(5, TimeUnit.SECONDS);
            if (isLocked) {
                System.out.println("获取锁成功,执行订单: " + orderId);
                // 业务逻辑
                processOrder(orderId);
            } else {
                System.out.println("获取锁失败");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            if (isLocked) {
                lock.unlock();
                System.out.println("释放锁");
            }
        }
    }
    private void processOrder(String orderId) {
        // 业务处理逻辑
        System.out.println("处理订单业务...");
    }
}

分布式锁实战应用示例

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.TimeUnit;
/**
 * 分布式锁实战 - 电商订单防重
 */
public class OrderLockService {
    private static final Logger logger = LoggerFactory.getLogger(OrderLockService.class);
    private RedissonClient redissonClient;
    public OrderLockService() {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://localhost:6379");
        redissonClient = Redisson.create(config);
    }
    /**
     * 创建订单(使用分布式锁防止重复提交)
     */
    public Result createOrder(OrderRequest request) {
        // 使用用户ID+商品ID作为锁的key
        String lockKey = "order:create:" + request.getUserId() + ":" + request.getProductId();
        RLock lock = redissonClient.getLock(lockKey);
        try {
            // 尝试获取锁,等待3秒
            if (!lock.tryLock(3, TimeUnit.SECONDS)) {
                return Result.fail("操作太频繁,请稍后再试");
            }
            logger.info("获取锁成功, userId={}, productId={}", 
                       request.getUserId(), request.getProductId());
            // 检查是否已存在订单
            if (checkOrderExist(request)) {
                return Result.fail("订单已存在,请勿重复提交");
            }
            // 创建订单
            Order order = createNewOrder(request);
            // 扣减库存
            reduceStock(request.getProductId(), request.getQuantity());
            return Result.success(order);
        } catch (Exception e) {
            logger.error("创建订单失败", e);
            return Result.fail("系统异常,请稍后再试");
        } finally {
            // 释放锁
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
                logger.info("释放锁成功");
            }
        }
    }
    /**
     * 模拟多线程并发下单测试
     */
    public void testConcurrentOrder() {
        int threadCount = 10;
        CountDownLatch latch = new CountDownLatch(threadCount);
        for (int i = 0; i < threadCount; i++) {
            final int userId = i;
            new Thread(() -> {
                try {
                    latch.await();
                    OrderRequest request = new OrderRequest();
                    request.setUserId(userId);
                    request.setProductId(1001L);
                    request.setQuantity(1);
                    Result result = createOrder(request);
                    System.out.println("用户" + userId + "下单结果: " + result);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
            latch.countDown();
        }
    }
    private boolean checkOrderExist(OrderRequest request) {
        // 查询数据库检查订单是否存在
        return false;
    }
    private Order createNewOrder(OrderRequest request) {
        // 创建订单逻辑
        return new Order();
    }
    private void reduceStock(Long productId, Integer quantity) {
        // 扣减库存逻辑
    }
    // 辅助类
    static class OrderRequest {
        private Integer userId;
        private Long productId;
        private Integer quantity;
        // getters and setters...
        public Integer getUserId() { return userId; }
        public void setUserId(Integer userId) { this.userId = userId; }
        public Long getProductId() { return productId; }
        public void setProductId(Long productId) { this.productId = productId; }
        public Integer getQuantity() { return quantity; }
        public void setQuantity(Integer quantity) { this.quantity = quantity; }
    }
    static class Order {
        private Long id;
        private Integer userId;
        // ...
    }
    static class Result {
        private boolean success;
        private String message;
        private Object data;
        public static Result success(Object data) {
            Result result = new Result();
            result.success = true;
            result.data = data;
            return result;
        }
        public static Result fail(String message) {
            Result result = new Result();
            result.success = false;
            result.message = message;
            return result;
        }
        @Override
        public String toString() {
            return "Result{success=" + success + ", message='" + message + "'}";
        }
    }
}

分布式锁配置类

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.integration.redis.util.RedisLockRegistry;
@Configuration
public class DistributedLockConfig {
    /**
     * Redisson客户端配置
     */
    @Bean
    public RedissonClient redissonClient() {
        Config config = new Config();
        config.useSingleServer()
              .setAddress("redis://192.168.1.100:6379")
              .setPassword("123456")
              .setDatabase(0)
              .setConnectionPoolSize(50)
              .setConnectionMinimumIdleSize(10)
              .setTimeout(3000)
              .setRetryAttempts(3)
              .setRetryInterval(1500);
        return Redisson.create(config);
    }
    /**
     * Spring Integration 锁注册表
     */
    @Bean
    public RedisLockRegistry redisLockRegistry(RedisConnectionFactory connectionFactory) {
        return new RedisLockRegistry(connectionFactory, "spring-integration-lock", 30000);
    }
}

Maven依赖配置

<dependencies>
    <!-- Redis Jedis -->
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>3.7.0</version>
    </dependency>
    <!-- Redisson -->
    <dependency>
        <groupId>org.redisson</groupId>
        <artifactId>redisson</artifactId>
        <version>3.16.8</version>
    </dependency>
    <!-- ZooKeeper -->
    <dependency>
        <groupId>org.apache.zookeeper</groupId>
        <artifactId>zookeeper</artifactId>
        <version>3.6.3</version>
    </dependency>
    <!-- Spring Integration Redis -->
    <dependency>
        <groupId>org.springframework.integration</groupId>
        <artifactId>spring-integration-redis</artifactId>
        <version>5.5.15</version>
    </dependency>
    <!-- Spring Data Redis -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <!-- Lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

关键设计要点

Redis分布式锁注意事项

  • 原子性:使用SET NX EX命令确保原子操作
  • 唯一标识:每个锁必须有唯一标识,防止误删其他线程的锁
  • 过期时间:设置合理的过期时间,防止死锁
  • 看门狗机制:Redisson的看门狗可以自动续期

ZooKeeper分布式锁

  • 临时顺序节点:避免羊群效应
  • 监听机制:只监听前一个节点
  • 会话超时:处理心跳超时场景

最佳实践建议

// 锁的粒度设计
// - 细粒度:订单ID、用户ID
// - 粗粒度:库存、账户
// 超时时间设计
lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
// waitTime: 等待获取锁的时间
// leaseTime: 锁的持有时间
// 错误处理
catch (InterruptedException e) {
    Thread.currentThread().interrupt();
    // 恢复中断状态
}

这些案例涵盖了主流的分布式锁实现方案,您可以根据实际需求选择合适的方案,生产环境推荐使用Redisson,因为它提供了完善的自动续期机制和高可用支持。

上一篇可重入锁案例

下一篇SAGA案例

抱歉,评论功能暂时关闭!