Java分布式锁(6种实现方法)

Java分布式锁


方式优点缺点
数据库实现简单、易于理解对数据库压力大
Redis易于理解自己实现、不支持阻塞
Zookeeper支持阻塞需理解Zookeeper、程序复杂
Curator(推荐)提供锁的方法依赖Zookeeper、强一致
Redisson(推荐)提供锁的方法,可阻塞

一、基于ReentrantLock锁解决超卖问题(单体)

1.1、重要代码

package com.example.distributedemo.service;

import com.example.distributedemo.dao.OrderItemMapper;
import com.example.distributedemo.dao.OrderInfoMapper;
import com.example.distributedemo.dao.ProductMapper;
import com.example.distributedemo.model.orderInfo;
import com.example.distributedemo.model.OrderItem;
import com.example.distributedemo.model.Product;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

@Service
@Slf4j
public class OrderService {

    @Resource
    private OrderInfoMapper orderMapper;
    @Resource
    private OrderItemMapper orderItemMapper;
    @Resource
    private ProductMapper productMapper;
    
    //购买商品id
    private Integer  purchaseProductId = 1;
    //购买商品数量
    private int purchaseProductNum = 1;

    @Autowired
    private PlatformTransactionManager platformTransactionManager;
    @Autowired
    private TransactionDefinition transactionDefinition;

    private Lock lock = new ReentrantLock();


    public Integer createOrder() throws Exception{
        Product product = null;

        lock.lock();

        try {
            // 根据事务定义TransactionDefinition,获取事务
            TransactionStatus transaction1 = platformTransactionManager.getTransaction(transactionDefinition);
            product = productMapper.selectByPrimaryKey(purchaseProductId);
            if (product==null){
                // 回滚事务
                platformTransactionManager.rollback(transaction1);
                throw new Exception("购买商品:"+purchaseProductId+"不存在");
            }

            // 商品当前库存
            Integer currentCount = product.getCount();
            System.out.println(Thread.currentThread().getName()+"库存数:"+currentCount);
            // 校验库存
            if (purchaseProductNum > currentCount){
                // 回滚事务
                platformTransactionManager.rollback(transaction1);
                throw new Exception("商品"+purchaseProductId+"仅剩"+currentCount+"件,无法购买");
            }

            Product product1 = new Product();
            product1.setId(purchaseProductId);
            product1.setCount(0);

            productMapper.updateByPrimaryKeySelective(product1);
            // 提交事务
            platformTransactionManager.commit(transaction1);

        }finally {
            lock.unlock();
        }

        TransactionStatus transaction = platformTransactionManager.getTransaction(transactionDefinition);
        orderInfo order = new orderInfo();
        order.setId(1);
        order.setOrderName(product.getName());
        order.setAmount(product.getPrice().multiply(new BigDecimal(purchaseProductNum)));
        order.setOrderStatus(1);//待处理
        orderMapper.insertSelective(order);

        OrderItem orderItem = new OrderItem();
        orderItem.setId(1);
        orderItem.setOrderId(order.getId());
        orderItem.setProductId(product.getId());

        orderItemMapper.insertSelective(orderItem);
        platformTransactionManager.commit(transaction);

        return order.getId();
    }

}

1.2、测试代码

package com.example;

import com.example.distributedemo.DistributeDemoApplication;
import com.example.distributedemo.service.OrderService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = DistributeDemoApplication.class)
public class DistributeDemoApplicationTests {

    @Autowired
    private OrderService orderService;

    @Test
    public void concurrentOrder() throws InterruptedException {
        CountDownLatch cdl = new CountDownLatch(5);
        CyclicBarrier cyclicBarrier = new CyclicBarrier(5);
        ExecutorService es = Executors.newFixedThreadPool(5);

        for (int i =0;i<5;i++){
            es.execute(()->{
                try {
                    cyclicBarrier.await();
                    Integer orderId = orderService.createOrder();
                    System.out.println("订单id:"+orderId);
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    cdl.countDown();
                }
            });
        }
        cdl.await();
        es.shutdown();
    }

}

二、 基于数据库的分布式锁(分布式)

2.1、重要代码

package com.example.distributedemo.controller;

import com.example.distributedemo.dao.DistributeLockMapper;
import com.example.distributedemo.model.DistributeLock;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author zhuzhaoman
 * @date 2020/5/2 14:56
 * @description  基于数据库的分布式锁
 */
@Slf4j
@RestController
public class DemoController {

    @Resource
    private DistributeLockMapper distributeLockMapper;

    @RequestMapping("/singleLock")
    @Transactional(rollbackFor = Exception.class)
    public String singleLock() throws Exception {
        log.info("已经进入方法!");
        DistributeLock distributeLock = distributeLockMapper.selectDistributeLock("demo");
        if (distributeLock == null){
            throw new Exception("分布式锁找不到");
        }
        log.info("已经进入了锁!");
        Thread.sleep(30000);
        return "我已经执行完成!";
    }

}

2.2、重要sql语句

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.distributedemo.dao.DistributeLockMapper">
  <resultMap id="BaseResultMap" type="com.example.distributedemo.model.DistributeLock">
    <!--
      WARNING - @mbg.generated
    -->
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="business_code" jdbcType="VARCHAR" property="businessCode" />
    <result column="business_name" jdbcType="VARCHAR" property="businessName" />
  </resultMap>

  <select id="selectDistributeLock" resultType="com.example.distributedemo.model.DistributeLock">
    select *from distribute_lock
    where business_code = #{businessCode}
    for update
  </select>
</mapper>

2.3、测试

http://localhost:8081/singleLock
http://localhost:8082/singleLock

三、基于redis分布式锁

3.1、重要代码

package com.example.distributedemo.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.awt.print.Book;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;

/**
 * @author zhuzhaoman
 * @date 2020/5/2 0002 17:05
 * @description 基于redis分布式锁
 */

@RestController
@Slf4j
public class RedisLockController {

    @Autowired
    private RedisTemplate redisTemplate;

    @RequestMapping("/redisLock")
    public String redisLock() throws InterruptedException {
        log.info("我进入了方法");

        String key = "redisKey";
        String value = UUID.randomUUID().toString();

        RedisCallback<Boolean> redisCallback = redisConnection -> {
            // 设置NX
            RedisStringCommands.SetOption setOption = RedisStringCommands.SetOption.ifAbsent();
            // 设置过期时间
            Expiration expiration = Expiration.seconds(30);

            // 序列化key和value
            byte[] redisKey = redisTemplate.getKeySerializer().serialize(key);
            byte[] redisValue = redisTemplate.getValueSerializer().serialize(value);

            // 执行set nx 操作
            Boolean result = redisConnection.set(redisKey, redisValue, expiration, setOption);
            return result;
        };

        // 获取分布式锁
        Boolean lock = (Boolean) redisTemplate.execute(redisCallback);
        if (lock) {
            log.info("我进入了锁!");
            Thread.sleep(15000);
        }

        String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then\n" +
                "    return redis.call(\"del\",KEYS[1])\n" +
                "else\n" +
                "    return 0\n" +
                "end";
        RedisScript<Boolean> redisScript = RedisScript.of(script, Boolean.class);
        List<String> keys = Arrays.asList(key);

        Boolean result = (Boolean) redisTemplate.execute(redisScript, keys, value);
        log.info("释放锁的结果:" + result);


        log.info("方法执行完成");
        return "方法执行完成";
    }
}

3.2、yml配置

spring.datasource.username=root
spring.datasource.password=1999114zzm
spring.datasource.url=jdbc:mysql://localhost:3306/fen_bu_shi_suo?serverTimezone=Asia/Shanghai&useSSL=false


mybatis.mapper-locations=/mapper/*.xml
logging.pattern.dateformat=HH:mm:ss

spring.redis.host=你ip
spring.redis.port=6379

四、基于分布式锁解决定时任务重复问题

4.1、封装redis分布式锁

package com.example.distributedemo.lock;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.data.redis.core.types.Expiration;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;

/**
 * @author zhuzhaoman
 * @date 2020/5/2 0002 17:46
 * @description 描述
 */
@Slf4j
public class RedisLockUtils implements AutoCloseable{

    private RedisTemplate redisTemplate;
    private String key;
    private String value;
    // 单位:秒
    private int expireTime;

    public RedisLockUtils(RedisTemplate redisTemplate, String key, int expireTime) {
        this.redisTemplate = redisTemplate;
        this.key = key;
        this.value = UUID.randomUUID().toString();
        this.expireTime = expireTime;
    }

    /**
     * 获取分布式锁
     * @return
     */
    public boolean getLock() {
        RedisCallback<Boolean> redisCallback = redisConnection -> {
            // 设置NX
            RedisStringCommands.SetOption setOption = RedisStringCommands.SetOption.ifAbsent();
            // 设置过期时间
            Expiration expiration = Expiration.seconds(expireTime);

            // 序列化key和value
            byte[] redisKey = redisTemplate.getKeySerializer().serialize(key);
            byte[] redisValue = redisTemplate.getValueSerializer().serialize(value);

            // 执行set nx 操作
            Boolean result = redisConnection.set(redisKey, redisValue, expiration, setOption);
            return result;
        };

        // 获取分布式锁
        Boolean lock = (Boolean) redisTemplate.execute(redisCallback);

        return lock;
    }

    /**
     * 释放锁
     * @return
     */
    public boolean unLock() {
        String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then\n" +
                "    return redis.call(\"del\",KEYS[1])\n" +
                "else\n" +
                "    return 0\n" +
                "end";
        RedisScript<Boolean> redisScript = RedisScript.of(script, Boolean.class);
        List<String> keys = Arrays.asList(key);

        Boolean result = (Boolean) redisTemplate.execute(redisScript, keys, value);
        log.info("释放锁的结果:" + result);
        return result;
    }

    @Override
    public void close() throws Exception {
        // 释放锁
        unLock();
    }
}

4.2、重要代码

package com.example.distributedemo.controller;

import com.example.distributedemo.lock.RedisLockUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author zhuzhaoman
 * @date 2020/5/2 0002 17:05
 * @description 描述
 */

@RestController
@Slf4j
public class RedisLockController {

    @Autowired
    private RedisTemplate redisTemplate;

    @RequestMapping("/redisLock")
    public String redisLock() throws InterruptedException {
        log.info("我进入了方法");

        // 获取锁
        try(RedisLockUtils redisLock = new RedisLockUtils(redisTemplate, "redisKey", 30)) {

            boolean lock = redisLock.getLock();

            if (lock) {
                log.info("我进入了锁!");
                Thread.sleep(15000);
            }

        }catch (Exception e){
            e.printStackTrace();
        }

        log.info("方法执行完成");
        return "方法执行完成";
    }
}

4.3、解决任务重复

  • 启动类
package com.example.distributedemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
import tk.mybatis.spring.annotation.MapperScan;

@SpringBootApplication
@EnableScheduling // 开启定时任务
public class DistributeDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DistributeDemoApplication.class, args);
    }

}
  • 定时任务
package com.example.distributedemo.service;

import com.example.distributedemo.lock.RedisLockUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

/**
 * @author zhuzhaoman
 * @date 2020/5/2 0002 18:17
 * @description 描述
 */
@Service
@Slf4j
public class SchedulerService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Scheduled(cron = "0/5 * * * * ?")
    public void sendSms() {
        try(RedisLockUtils redisLock = new RedisLockUtils(redisTemplate, "autoSms", 30)) {
            boolean lock = redisLock.getLock();

            if (lock) {
                log.info("向138xxxxx用户发短信!");
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}

五、zookeeper分布式锁代码实现

5.1、重要代码

package com.example.distributedemo.lock;

import lombok.extern.slf4j.Slf4j;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import java.io.IOException;
import java.util.Collections;
import java.util.List;

/**
 * @author zhuzhaoman
 * @date 2020/5/2 0002 18:52
 * @description 描述
 */
@Slf4j
public class ZkLock implements AutoCloseable, Watcher {

    private ZooKeeper zooKeeper;
    private String znode;

    public ZkLock() throws IOException {
        this.zooKeeper = new ZooKeeper("49.232.26.207:2181", 60000, this);
    }

    public boolean getLock(String businessCode) {

        try {
            // 创建业务根节点
            Stat stat = zooKeeper.exists("/" + businessCode, false);
            if (stat==null){
                zooKeeper.create("/" + businessCode,
                        businessCode.getBytes(),
                        ZooDefs.Ids.OPEN_ACL_UNSAFE,
                        CreateMode.PERSISTENT);
            }

            // 创建瞬时有序节点 /order/order_序号
            znode = zooKeeper.create("/" + businessCode + "/" + businessCode + "_",
                    businessCode.getBytes(),
                    ZooDefs.Ids.OPEN_ACL_UNSAFE,
                    CreateMode.EPHEMERAL_SEQUENTIAL);

            // 获取业务节点下所有的子节点
            List<String> childrenNodes = zooKeeper.getChildren("/" + businessCode, false);
            // 子节点排序
            Collections.sort(childrenNodes);
            // 获取序列号最小的(第一个)子节点
            String firstNode = childrenNodes.get(0);
            // 如果创建的节点时第一个子节点,则获得锁
            if (znode.endsWith(firstNode)) {
                return true;
            }

            // 不是第一个子节点,则监听前一个节点
            String lastNode = firstNode;
            for (String node: childrenNodes){
                if (znode.endsWith(node)) {
                    zooKeeper.exists("/" + businessCode + "/" + lastNode, true);
                    break;
                } else {
                    lastNode = node;
                }
            }

            synchronized (this) {
                wait();
            }

            return true;
        }catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }

    @Override
    public void process(WatchedEvent watchedEvent) {
        if (watchedEvent.getType() == Event.EventType.NodeDeleted) {
            synchronized (this) {
                notify();
            }
        }
    }

    @Override
    public void close() throws Exception {
        zooKeeper.delete(znode, -1);
        zooKeeper.close();
        log.info("锁被释放");
    }
}

5.2、测试代码

package com.example.distributedemo.controller;

import com.example.distributedemo.lock.ZkLock;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author zhuzhaoman
 * @date 2020/5/2 0002 19:45
 * @description 描述
 */

@RestController
@Slf4j
public class ZookeeperController {

    @RequestMapping("/zkLock")
    public String zookeeperLock() {
        log.info("我进入了方法");
        try(ZkLock zkLock = new ZkLock()) {
            boolean order = zkLock.getLock("order");
            if (order) {
                log.info("获得了锁!");
                Thread.sleep(10000);
            }
        }catch (Exception e){
            e.printStackTrace();
        }

        log.info("方法执行完成!");

        return "方法执行完成!";
    }
}

六、基于curator分布式锁(推荐)

6.1、Application启动类

package com.example.distributedemo;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableScheduling;
import tk.mybatis.spring.annotation.MapperScan;

@SpringBootApplication
public class DistributeDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DistributeDemoApplication.class, args);
    }

    @Bean(initMethod = "start", destroyMethod = "close")
    public CuratorFramework getCuratorFramework() {
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(30000, 3);
        CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient("49.232.26.207:2181", retryPolicy);
        return curatorFramework;
    }

}

6.2、测试代码

package com.example.distributedemo.controller;

import com.example.distributedemo.lock.ZkLock;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit;

/**
 * @author zhuzhaoman
 * @date 2020/5/2 0002 19:45
 * @description 描述
 */

@RestController
@Slf4j
public class ZookeeperController {

    @Autowired
    private CuratorFramework curatorFramework;

    @RequestMapping("/curatorLock")
    public String curatorLock() throws Exception {
        log.info("我进入了方法");

        InterProcessMutex lock = new InterProcessMutex(curatorFramework, "/order");
        try {
            if (lock.acquire(30, TimeUnit.SECONDS)) {
                log.info("我获得了锁!");
                Thread.sleep(10000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            log.info("释放了锁");
            lock.release();
        }

        log.info("方法执行完成!");

        return "方法执行完成!";
    }
}

七、基于redisson分布式锁(推荐)

7.1、测试代码

package com.example.distributedemo.controller;

import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit;

/**
 * @author zhuzhaoman
 * @date 2020/5/2 0002 16:53
 * @description 描述
 */

@RestController
@Slf4j
public class RedissonLockController {

    @RequestMapping("/redissonLock")
    public String redissonLock() throws InterruptedException {

        Config config = new Config();
        config.useSingleServer().setAddress("redis://49.232.26.207:6379");
        RedissonClient redissonClient = Redisson.create(config);

        RLock rLock = redissonClient.getLock("order");
        log.info("我进入了方法");

        rLock.lock(30, TimeUnit.SECONDS);
        log.info("获得了锁");
        Thread.sleep(15000);
        log.info("释放了锁");
        rLock.unlock();
        log.info("方法执行完成");

        return "方法执行完成";
    }
}

八、springboot引入redisson(推荐)

8.1、配置文件

spring.datasource.username=root
spring.datasource.password=1999114zzm
spring.datasource.url=jdbc:mysql://localhost:3306/fen_bu_shi_suo?serverTimezone=Asia/Shanghai&useSSL=false


mybatis.mapper-locations=/mapper/*.xml
logging.pattern.dateformat=HH:mm:ss

spring.redis.host=49.232.26.207
spring.redis.port=6379

8.2、测试文件

package com.example.distributedemo.controller;

import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

/**
 * @author zhuzhaoman
 * @date 2020/5/2 0002 16:53
 * @description 描述
 */

@RestController
@Slf4j
public class RedissonLockController {

    @Autowired
    private RedissonClient redissonClient;

    @RequestMapping("/redissonLock")
    public String redissonLock() throws InterruptedException {

        RLock rLock = redissonClient.getLock("order");
        log.info("我进入了方法");

        rLock.lock(30, TimeUnit.SECONDS);
        log.info("获得了锁");
        Thread.sleep(15000);
        log.info("释放了锁");
        rLock.unlock();
        log.info("方法执行完成");

        return "方法执行完成";
    }
}

九、完整的pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>distribute-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>distribute-demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.11.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.6.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>4.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>3.11.2</version>
        </dependency>

        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.3.3</version>
        </dependency>
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper</artifactId>
            <version>4.1.5</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.11</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.7</version>
                <dependencies>
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>8.0.17</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>

</project>

  • 11
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java分布式锁实现方式有多,常见的包括: 1. 基于Redis分布式锁:利用Redis单线程的特性,使用SETNX命令创建锁,利用EXPIRE设置锁的过期时间,同时使用DEL命令释放锁,确保锁的释放是原子的。 2. 基于Zookeeper分布式锁:通过创建临时节点实现分布式锁,当某个服务占用了锁,其它服务将无法创建同名节点,从而保证同一时间只有一个服务占用该锁。 3. 基于数据库的分布式锁:使用数据库表中的一行记录来表示锁状态,使用事务确保锁的获取和释放是原子的。 4. 基于Redisson的分布式锁Redisson是一个开源的Java分布式框架,提供了对分布式锁的支持,使用SETNX和EXPIRE命令实现锁的创建和过期,同时还提供了自旋锁、可重入锁等高级特性。 以上是Java分布式锁实现方式的几常见方式,不同的实现方式有着各自的特点和适用场景,需要根据实际需求进行选择。 ### 回答2: Java分布式锁分布式系统中实现数据同步和控制的关键技术之一,它用于保证多个分布式进程并发访问共享资源时的数据一致性和安全性。分布式锁与普通的锁相比,需要解决跨进程、跨节点的同步和并发控制问题。 Java分布式锁实现方式有以下几: 1. 基于Zookeeper实现分布式锁 Zookeeper是一个高性能的分布式协调服务,它可以被用来实现分布式锁Zookeeper实现原理是基于它的强一致性和顺序性,可以保证多个进程访问同一个分布式锁时的数据同步和控制。 通过创建一个Zookeeper的持久节点来实现分布式锁,使用create()方法来创建节点,如果创建成功则说明获取锁成功。当多个进程同时请求获取锁时,只有一个进程能够创建节点成功,其它进程只能等待。当持有分布式锁的进程退出时,Zookeeper会自动删除对应的节点,其它进程就可以继续请求获取锁。 2. 基于Redis实现分布式锁 Redis是高性能的内存数据库,可以使用它的setnx()命令来实现分布式锁。setnx()命令可以在指定的key不存在时设置key的值,并返回1;如果key已经存在,则返回0。通过这个原子性的操作来实现分布式锁。 当多个进程同时请求获取锁时,只有一个进程能够成功执行setnx()命令,其它进程只能等待。进程在持有锁期间,可以利用Redis的expire()命令来更新锁的过期时间。当持有分布式锁的进程退出时,可以通过delete()命令来删除锁。 3. 基于数据库实现分布式锁 数据库通过ACID特性来保证数据的一致性、并发性和可靠性,可以通过在数据库中创建一个唯一索引来实现分布式锁。当多个进程同时请求获取锁时,只有一个进程能够成功插入唯一索引,其它进程只能等待。当持有分布式锁的进程退出时,可以通过删除索引中对应的记录来释放锁。 不同的实现方式各有优劣。基于Zookeeper实现方式可以保证分布式锁的一致性和可靠性,但是需要引入额外的依赖;基于Redis可以实现较高性能的分布式锁,但是在高并发条件下可能会存在死锁等问题;基于数据库的实现方式简单,但在高并发条件下也可能会有锁争抢等问题。 总之,在选择分布式锁实现方式时,需要根据业务场景和需求来综合考虑各因素,选择最适合自己的方式。 ### 回答3: 分布式系统中的并发控制是解决分布式系统中竞争资源的重要问题之一,而分布式锁作为一并发控制工具,在分布式系统中被广泛采用。Java作为一常用的编程语言,在分布式锁实现方面也提供了多解决方案。下面就分别介绍Java分布式锁实现方式。 1. 基于ZooKeeper分布式锁 ZooKeeper分布式系统中常用的协调工具,其提供了一套完整的API用于实现分布式锁实现分布式锁的过程中需要创建一个Znode,表示锁,同时用于控制数据的访问。在这个Znode上注册监听器用于接收释放锁的成功/失败事件,从而控制加锁/解锁的过程。 2. 基于Redis分布式锁 Redis作为一高性能的Key-Value数据库,其提供了完整的API用于实现分布式锁实现分布式锁的过程中需要在Redis中创建一个Key,利用Redis的SETNX命令进行加锁,同时设置过期时间保证锁的生命周期。在解锁时需要判断是否持有锁并删除对应的Key。 3. 基于数据库的分布式锁 数据库作为分布式系统中常用的数据存储方式,其提供了事务机制用于实现分布式锁。在实现分布式锁的过程中需要在数据库中创建一个表,利用数据库的事务机制实现加锁/解锁,同时需要设置过期时间保证锁的生命周期。 总之,以上三方式都是常用的Java分布式锁实现方式。选择合适的方法需要综合考虑锁的使用场景、性能需求、可靠性要求等因素。同时,在实现分布式锁的过程中需要注意锁的加锁/解锁的正确性和过期时间的设置,保证分布式系统的并发控制的正确性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值