Spring Boot 分布式锁与并发控制的应用场景

 更新时间:2026年03月26日 11:48:47   作者:星辰徐哥  
本章主要介绍了SpringBoot分布式锁与并发控制的核心概念与使用方法,包括分布式锁的定义与特点、并发控制的定义与特点、SpringBoot与分布式锁的集成、SpringBoot的实际应用场景,感兴趣的朋友跟随小编一起看看吧

Spring Boot 分布式锁与并发控制

30.1 学习目标与重点提示

学习目标:掌握Spring Boot分布式锁与并发控制的核心概念与使用方法,包括分布式锁的定义与特点、并发控制的定义与特点、Spring Boot与分布式锁的集成、Spring Boot的实际应用场景,学会在实际开发中处理分布式锁与并发控制问题。
重点:分布式锁的定义与特点并发控制的定义与特点Spring Boot与分布式锁的集成Spring Boot的实际应用场景

30.2 分布式锁与并发控制概述

分布式锁与并发控制是Java开发中的重要组件,用于处理分布式系统中的并发访问问题。

30.2.1 分布式锁的定义

定义:分布式锁是一种用于在分布式系统中实现资源共享访问控制的机制,确保在同一时间只有一个进程或线程能够访问共享资源。
作用

  • 防止资源的并发修改。
  • 确保数据的一致性。
  • 提高系统的可靠性。

常见的分布式锁

  • Redis分布式锁:Redis是一种开源的内存数据库,支持分布式锁。
  • Zookeeper分布式锁:Zookeeper是一种开源的分布式协调服务,支持分布式锁。
  • Etcd分布式锁:Etcd是一种开源的分布式键值存储系统,支持分布式锁。

✅ 结论:分布式锁是一种用于在分布式系统中实现资源共享访问控制的机制,作用是防止资源的并发修改、确保数据的一致性、提高系统的可靠性。

30.2.2 并发控制的定义

定义:并发控制是指在多进程或多线程环境中,控制对共享资源的访问,防止数据不一致和并发冲突。
作用

  • 防止数据不一致。
  • 防止并发冲突。
  • 提高系统的性能。

常见的并发控制技术

  • 锁机制:包括悲观锁和乐观锁。
  • 事务机制:包括ACID属性。
  • 并发集合:包括ConcurrentHashMap和CopyOnWriteArrayList。

✅ 结论:并发控制是指在多进程或多线程环境中,控制对共享资源的访问,作用是防止数据不一致、防止并发冲突、提高系统的性能。

30.3 Spring Boot与分布式锁的集成

Spring Boot与分布式锁的集成是Java开发中的重要内容。

30.3.1 集成Redis分布式锁的步骤

定义:集成Redis分布式锁的步骤是指使用Spring Boot与Redis分布式锁集成的方法。
步骤

  1. 创建Spring Boot项目。
  2. 添加所需的依赖。
  3. 配置Redis。
  4. 创建分布式锁工具类。
  5. 创建业务层。
  6. 创建控制器类。
  7. 测试应用。

示例
pom.xml文件中的依赖:

<dependencies>
    <!-- Web依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- Redis依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <!-- 测试依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

application.properties文件中的配置:

# 服务器端口
server.port=8080
# Redis连接信息
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=
spring.redis.database=0

分布式锁工具类:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
public class RedisLock {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    private static final String LOCK_KEY = "product-lock";
    private static final long LOCK_EXPIRE_TIME = 30; // 锁的过期时间,单位秒
    public boolean tryLock(String lockValue) {
        Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(LOCK_KEY, lockValue, LOCK_EXPIRE_TIME, TimeUnit.SECONDS);
        return Boolean.TRUE.equals(result);
    }
    public void releaseLock(String lockValue) {
        String value = stringRedisTemplate.opsForValue().get(LOCK_KEY);
        if (lockValue.equals(value)) {
            stringRedisTemplate.delete(LOCK_KEY);
        }
    }
}

实体类:

public class Product {
    private Long id;
    private String productId;
    private String productName;
    private double price;
    private int stock;
    public Product() {
    }
    public Product(Long id, String productId, String productName, double price, int stock) {
        this.id = id;
        this.productId = productId;
        this.productName = productName;
        this.price = price;
        this.stock = stock;
    }
    // Getter和Setter方法
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getProductId() {
        return productId;
    }
    public void setProductId(String productId) {
        this.productId = productId;
    }
    public String getProductName() {
        return productName;
    }
    public void setProductName(String productName) {
        this.productName = productName;
    }
    public double getPrice() {
        return price;
    }
    public void setPrice(double price) {
        this.price = price;
    }
    public int getStock() {
        return stock;
    }
    public void setStock(int stock) {
        this.stock = stock;
    }
    @Override
    public String toString() {
        return "Product{" +
                "id=" + id +
                ", productId='" + productId + '\'' +
                ", productName='" + productName + '\'' +
                ", price=" + price +
                ", stock=" + stock +
                '}';
    }
}

Repository接口:

import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Repository
public class ProductRepository {
    private List<Product> products = new ArrayList<>();
    public ProductRepository() {
        products.add(new Product(1L, "P001", "手机", 1000.0, 100));
        products.add(new Product(2L, "P002", "电脑", 5000.0, 50));
        products.add(new Product(3L, "P003", "电视", 3000.0, 80));
        products.add(new Product(4L, "P004", "手表", 500.0, 200));
        products.add(new Product(5L, "P005", "耳机", 300.0, 150));
    }
    public List<Product> getAllProducts() {
        return products;
    }
    public Product getProductById(Long id) {
        return products.stream().filter(product -> product.getId().equals(id)).findFirst().orElse(null);
    }
    public void addProduct(Product product) {
        product.setId((long) (products.size() + 1));
        products.add(product);
    }
    public void updateProduct(Product product) {
        Product existingProduct = getProductById(product.getId());
        if (existingProduct != null) {
            existingProduct.setProductId(product.getProductId());
            existingProduct.setProductName(product.getProductName());
            existingProduct.setPrice(product.getPrice());
            existingProduct.setStock(product.getStock());
        }
    }
    public void deleteProduct(Long id) {
        products.removeIf(product -> product.getId().equals(id));
    }
}

Service类:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.UUID;
@Service
public class ProductService {
    @Autowired
    private ProductRepository productRepository;
    @Autowired
    private RedisLock redisLock;
    public List<Product> getAllProducts() {
        return productRepository.getAllProducts();
    }
    public Product getProductById(Long id) {
        return productRepository.getProductById(id);
    }
    public void addProduct(Product product) {
        productRepository.addProduct(product);
    }
    public void updateProduct(Product product) {
        productRepository.updateProduct(product);
    }
    public void deleteProduct(Long id) {
        productRepository.deleteProduct(id);
    }
    public boolean reduceStock(Long id, int quantity) {
        String lockValue = UUID.randomUUID().toString();
        try {
            if (redisLock.tryLock(lockValue)) {
                Product product = productRepository.getProductById(id);
                if (product != null && product.getStock() >= quantity) {
                    product.setStock(product.getStock() - quantity);
                    productRepository.updateProduct(product);
                    return true;
                }
                return false;
            }
            return false;
        } finally {
            redisLock.releaseLock(lockValue);
        }
    }
}

控制器类:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/products")
public class ProductController {
    @Autowired
    private ProductService productService;
    @GetMapping("/")
    public List<Product> getAllProducts() {
        return productService.getAllProducts();
    }
    @GetMapping("/{id}")
    public Product getProductById(@PathVariable Long id) {
        return productService.getProductById(id);
    }
    @PostMapping("/add")
    public void addProduct(@RequestBody Product product) {
        productService.addProduct(product);
    }
    @PutMapping("/edit/{id}")
    public void editProduct(@PathVariable Long id, @RequestBody Product product) {
        product.setId(id);
        productService.updateProduct(product);
    }
    @DeleteMapping("/delete/{id}")
    public void deleteProduct(@PathVariable Long id) {
        productService.deleteProduct(id);
    }
    @PostMapping("/reduceStock/{id}/{quantity}")
    public boolean reduceStock(@PathVariable Long id, @PathVariable int quantity) {
        return productService.reduceStock(id, quantity);
    }
}

应用启动类:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RedisLockApplication {
    public static void main(String[] args) {
        SpringApplication.run(RedisLockApplication.class, args);
    }
}

测试类:

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class RedisLockApplicationTests {
    @LocalServerPort
    private int port;
    @Autowired
    private TestRestTemplate restTemplate;
    @Test
    void contextLoads() {
    }
    @Test
    void testGetAllProducts() {
        List products = restTemplate.getForObject("http://localhost:" + port + "/api/products/", List.class);
        assertThat(products).hasSize(5);
    }
    @Test
    void testReduceStock() {
        boolean result = restTemplate.postForObject("http://localhost:" + port + "/api/products/reduceStock/1/10", null, Boolean.class);
        assertThat(result).isTrue();
    }
}

✅ 结论:集成Redis分布式锁的步骤包括创建Spring Boot项目、添加所需的依赖、配置Redis、创建分布式锁工具类、创建业务层、创建控制器类、测试应用。

30.4 Spring Boot的实际应用场景

在实际开发中,Spring Boot分布式锁与并发控制的应用场景非常广泛,如:

  • 实现产品库存的并发扣减。
  • 实现用户账户的并发扣款。
  • 实现订单的并发创建。
  • 实现数据的并发更新。

示例

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.UUID;
@Service
class ProductService {
    @Autowired
    private ProductRepository productRepository;
    @Autowired
    private RedisLock redisLock;
    public List<Product> getAllProducts() {
        return productRepository.getAllProducts();
    }
    public Product getProductById(Long id) {
        return productRepository.getProductById(id);
    }
    public void addProduct(Product product) {
        productRepository.addProduct(product);
    }
    public void updateProduct(Product product) {
        productRepository.updateProduct(product);
    }
    public void deleteProduct(Long id) {
        productRepository.deleteProduct(id);
    }
    public boolean reduceStock(Long id, int quantity) {
        String lockValue = UUID.randomUUID().toString();
        try {
            if (redisLock.tryLock(lockValue)) {
                Product product = productRepository.getProductById(id);
                if (product != null && product.getStock() >= quantity) {
                    product.setStock(product.getStock() - quantity);
                    productRepository.updateProduct(product);
                    return true;
                }
                return false;
            }
            return false;
        } finally {
            redisLock.releaseLock(lockValue);
        }
    }
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
class RedisLock {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    private static final String LOCK_KEY = "product-lock";
    private static final long LOCK_EXPIRE_TIME = 30;
    public boolean tryLock(String lockValue) {
        Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(LOCK_KEY, lockValue, LOCK_EXPIRE_TIME, TimeUnit.SECONDS);
        return Boolean.TRUE.equals(result);
    }
    public void releaseLock(String lockValue) {
        String value = stringRedisTemplate.opsForValue().get(LOCK_KEY);
        if (lockValue.equals(value)) {
            stringRedisTemplate.delete(LOCK_KEY);
        }
    }
}
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Repository
class ProductRepository {
    private List<Product> products = new ArrayList<>();
    public ProductRepository() {
        products.add(new Product(1L, "P001", "手机", 1000.0, 100));
        products.add(new Product(2L, "P002", "电脑", 5000.0, 50));
        products.add(new Product(3L, "P003", "电视", 3000.0, 80));
        products.add(new Product(4L, "P004", "手表", 500.0, 200));
        products.add(new Product(5L, "P005", "耳机", 300.0, 150));
    }
    public List<Product> getAllProducts() {
        return products;
    }
    public Product getProductById(Long id) {
        return products.stream().filter(product -> product.getId().equals(id)).findFirst().orElse(null);
    }
    public void addProduct(Product product) {
        product.setId((long) (products.size() + 1));
        products.add(product);
    }
    public void updateProduct(Product product) {
        Product existingProduct = getProductById(product.getId());
        if (existingProduct != null) {
            existingProduct.setProductId(product.getProductId());
            existingProduct.setProductName(product.getProductName());
            existingProduct.setPrice(product.getPrice());
            existingProduct.setStock(product.getStock());
        }
    }
    public void deleteProduct(Long id) {
        products.removeIf(product -> product.getId().equals(id));
    }
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/products")
class ProductController {
    @Autowired
    private ProductService productService;
    @GetMapping("/")
    public List<Product> getAllProducts() {
        return productService.getAllProducts();
    }
    @GetMapping("/{id}")
    public Product getProductById(@PathVariable Long id) {
        return productService.getProductById(id);
    }
    @PostMapping("/add")
    public void addProduct(@RequestBody Product product) {
        productService.addProduct(product);
    }
    @PutMapping("/edit/{id}")
    public void editProduct(@PathVariable Long id, @RequestBody Product product) {
        product.setId(id);
        productService.updateProduct(product);
    }
    @DeleteMapping("/delete/{id}")
    public void deleteProduct(@PathVariable Long id) {
        productService.deleteProduct(id);
    }
    @PostMapping("/reduceStock/{id}/{quantity}")
    public boolean reduceStock(@PathVariable Long id, @PathVariable int quantity) {
        return productService.reduceStock(id, quantity);
    }
}
@SpringBootApplication
public class RedisLockApplication {
    public static void main(String[] args) {
        SpringApplication.run(RedisLockApplication.class, args);
    }
}
// 测试类
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class RedisLockApplicationTests {
    @LocalServerPort
    private int port;
    @Autowired
    private TestRestTemplate restTemplate;
    @Test
    void contextLoads() {
    }
    @Test
    void testGetAllProducts() {
        List products = restTemplate.getForObject("http://localhost:" + port + "/api/products/", List.class);
        assertThat(products).hasSize(5);
    }
    @Test
    void testReduceStock() {
        boolean result = restTemplate.postForObject("http://localhost:" + port + "/api/products/reduceStock/1/10", null, Boolean.class);
        assertThat(result).isTrue();
    }
}

输出结果

  • 访问http://localhost:8080/api/products/:返回所有产品信息。
  • 访问http://localhost:8080/api/products/reduceStock/1/10:返回true,表示库存扣减成功。

✅ 结论:在实际开发中,Spring Boot分布式锁与并发控制的应用场景非常广泛,需要根据实际问题选择合适的分布式锁和并发控制方法。

总结

本章我们学习了Spring Boot分布式锁与并发控制,包括分布式锁的定义与特点、并发控制的定义与特点、Spring Boot与分布式锁的集成、Spring Boot的实际应用场景,学会了在实际开发中处理分布式锁与并发控制问题。其中,分布式锁的定义与特点、并发控制的定义与特点、Spring Boot与分布式锁的集成、Spring Boot的实际应用场景是本章的重点内容。从下一章开始,我们将学习Spring Boot的其他组件、微服务等内容。

到此这篇关于Spring Boot 分布式锁与并发控制的应用场景的文章就介绍到这了,更多相关Spring Boot 分布式锁与并发控制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解SpringIOC BeanDeifition

    详解SpringIOC BeanDeifition

    这篇文章主要介绍了SpringIOC BeanDeifition的相关资料,帮助大家更好的理解和学习springioc,感兴趣的朋友可以了解下
    2020-12-12
  • SpringBoot详解整合Spring Boot Admin实现监控功能

    SpringBoot详解整合Spring Boot Admin实现监控功能

    这篇文章主要介绍了SpringBoot整合Spring Boot Admin实现服务监控,内容包括Server端服务开发,Client端服务开发其中Spring Boot Admin还可以对其监控的服务提供告警功能,如服务宕机时,可以及时以邮件方式通知运维人员,感兴趣的朋友跟随小编一起看看吧
    2022-07-07
  • 详解spring applicationContext.xml 配置文件

    详解spring applicationContext.xml 配置文件

    本篇文章主要介绍了详解spring applicationContext.xml 配置文件 ,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-02-02
  • POST方法给@RequestBody传参数失败的解决及原因分析

    POST方法给@RequestBody传参数失败的解决及原因分析

    这篇文章主要介绍了POST方法给@RequestBody传参数失败的解决及原因分析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • Spring 框架中注入或替换方法实现

    Spring 框架中注入或替换方法实现

    这篇文章主要介绍了Spring 框架中注入或替换方法实现,非常不错,具有参考借鉴价值,感兴趣的朋友跟随脚本之家小编一起学习吧
    2018-05-05
  • Java拦截器、过滤器和监听器的区别与作用详解

    Java拦截器、过滤器和监听器的区别与作用详解

    Java 拦截器、过滤器和监听器是在 Java Web 开发中常用的组件,它们各有特点和用途,下面将分别介绍它们的区别和作用,并提供具体的代码示例,需要的朋友可以参考下
    2025-06-06
  • maven三个常用的插件使用介绍

    maven三个常用的插件使用介绍

    大家好,本篇文章主要讲的是maven三个常用的插件使用介绍,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览
    2021-12-12
  • MyBatis嵌套查询collection报错:org.apache.ibatis.exceptions.TooManyResultsException

    MyBatis嵌套查询collection报错:org.apache.ibatis.exceptions.TooMany

    本文主要介绍了MyBatis嵌套查询collection报错:org.apache.ibatis.exceptions.TooManyResultsException,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-09-09
  • Docker环境下Spring Boot应用内存飙升分析与解决场景分析

    Docker环境下Spring Boot应用内存飙升分析与解决场景分析

    当运行一个Spring Boot项目时,如果未设置JVM内存参数,Spring Boot默认会采用JVM自身默认的配置策略,接下来通过本文给大家介绍Docker环境下Spring Boot应用内存飙升分析与解决方法,需要的朋友参考下吧
    2021-08-08
  • Java实现PDF转图片的三种方法

    Java实现PDF转图片的三种方法

    有些时候我们需要在项目中展示PDF,所以我们可以将PDF转为图片,然后已图片的方式展示,效果很好,Java使用各种技术将pdf转换成图片格式,并且内容不失帧,本文给大家介绍了三种方法实现PDF转图片的案例,需要的朋友可以参考下
    2023-10-10

最新评论