Java单体项目和分布式项目中的锁

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: Java单体项目和分布式项目中的锁Java单体项目和分布式项目中的锁

单体应用解决超卖问题

@Service
@Slf4j
public class OrderService {
    @Resource
    private OrderMapper orderMapper;
    @Resource
    private OrderItemMapper orderItemMapper;
    @Resource
    private ProductMapper productMapper;
    //购买商品id
    private int purchaseProductId = 100100;
    //购买商品数量
    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 {
            //手动开启事务
            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+"件,无法购买");
            }
            productMapper.updateProductCount(purchaseProductNum,"xxx",new Date(),product.getId());
            //正常执行,提交事务
            platformTransactionManager.commit(transaction1);
        }finally {
            // 释放锁
            lock.unlock();
        }
      // 其他创建订单业务逻辑
    }
}

我们再finally里面释放锁,方法还未结束,事务还未提交,高并发下,恰好在锁释放后,事务提交前,读到了未提交的脏数据,导致超卖!

解决上述问题,需要使用aop锁

1、定义注解:

@Target({ElementType.PARAMETER,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ServiceLock {
    String description() default "";
}

2、定义切面

@Component
@Scope
@Aspect
@Order(1) // 表示在事务之前执行
public class LockAspect {
    // 定义锁对象
    private static Lock lock = new ReentrantLock(true);
    @Pointcut("@annotation(com.sugo.seckill.aop.lock.ServiceLock)")
    public void lockAspect(){
    }
    // 增强方法
    @Around("lockAspect()")
    public Object around(ProceedingJoinPoint joinPoint){
        Object obj = null;
        // 加锁
        lock.lock();
        // 执行业务
        try {
            obj = joinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        } finally {
            // 释放锁
            lock.unlock();
        }
        return obj;
    }
}

3、使用注解

@Transactional
  @ServiceLock
  @Override
  public HttpResult startKilledByLocked(Long killId, String userId) {
    try {
      // 从数据库查询商品数据
      TbSeckillGoods seckillGoods = seckillGoodsMapper.selectByPrimaryKey(killId);
      //判断
      if(seckillGoods == null){
        return HttpResult.error(HttpStatus.SEC_GOODS_NOT_EXSISTS,"商品不存在");
      }
      if(seckillGoods.getStatus() != 1){
        return HttpResult.error(HttpStatus.SEC_NOT_UP,"商品未审核");
      }
      if(seckillGoods.getStockCount() <= 0){
        return HttpResult.error(HttpStatus.SEC_GOODS_END,"商品已售罄");
      }
      if(seckillGoods.getStartTimeDate().getTime() > new Date().getTime()){
        return HttpResult.error(HttpStatus.SEC_ACTIVE_NOT_START,"活动未开始");
      }
      if(seckillGoods.getEndTimeDate().getTime() <= new Date().getTime()){
        return HttpResult.error(HttpStatus.SEC_ACTIVE_END,"活动结束");
      }
      //库存扣减
      seckillGoods.setStockCount(seckillGoods.getStockCount() - 1);
      //更新库存
      seckillGoodsMapper.updateByPrimaryKeySelective(seckillGoods);
      //下单
      TbSeckillOrder order = new TbSeckillOrder();
      order.setSeckillId(killId);
      order.setUserId(userId);
      order.setCreateTime(new Date());
      order.setStatus("0");
      order.setMoney(seckillGoods.getCostPrice());
      seckillOrderMapper.insertSelective(order);
      return HttpResult.ok("秒杀成功");
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }

分布式锁

基于Redis实现分布式锁

依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

定义RedisLock

@Slf4j
public class RedisLock implements AutoCloseable {
    private RedisTemplate redisTemplate;
    private String key;
    private String value;
    //单位:秒
    private int expireTime;
    public RedisLock(RedisTemplate redisTemplate,String key,int expireTime){
        this.redisTemplate = redisTemplate;
        this.key = key;
        this.expireTime=expireTime;
        this.value = UUID.randomUUID().toString();
    }
    /**
     * 获取分布式锁
     * @return
     */
    public boolean getLock(){
        RedisCallback<Boolean> redisCallback = connection -> {
            //设置NX
            RedisStringCommands.SetOption setOption = RedisStringCommands.SetOption.ifAbsent();
            //设置过期时间
            Expiration expiration = Expiration.seconds(expireTime);
            //序列化key
            byte[] redisKey = redisTemplate.getKeySerializer().serialize(key);
            //序列化value
            byte[] redisValue = redisTemplate.getValueSerializer().serialize(value);
            //执行setnx操作
            Boolean result = connection.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;
    }
    /**
     * 实现了AutoCloseable,实现自动释放锁,避免忘记释放锁
     * @throws Exception
     */
    @Override
    public void close() throws Exception {
        unLock();
    }
}

使用RedisLock

@RestController
@Slf4j
public class RedisLockController {
    @Autowired
    private RedisTemplate redisTemplate;
    @RequestMapping("redisLock")
    public String redisLock(){
        log.info("我进入了方法!");
        // redisKey是业务key,可以自定义
        try (RedisLock redisLock = new RedisLock(redisTemplate,"redisKey",30)){
            if (redisLock.getLock()) {
                log.info("我进入了锁!!");
                // 这里可以写具体并发业务
                Thread.sleep(15000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info("方法执行完成");
        return "方法执行完成";
    }
}

使用RedisLock就可以用@Scheduled实现分布式定时任务(启动类上要加@EnableScheduling)

@Service
@Slf4j
public class SchedulerService {
    @Autowired
    private RedisTemplate redisTemplate;
    @Scheduled(cron = "0/5 * * * * ?")
    public void sendSms(){
        // autoSms 是业务key, 可以自定义
        try(RedisLock redisLock = new RedisLock(redisTemplate,"autoSms",30)) {
            if (redisLock.getLock()){
                log.info("向138xxxxxxxx发送短信!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

上面同样有锁失效的问题,所以同样有Redis aop锁,具体实现如下:

@Target({ElementType.PARAMETER,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ServiceRedisLock {
    String description() default "";
}
@Component
@Scope
@Aspect
@Order(1) // 表示在事务之前执行
public class LockRedisAspect {
    @Pointcut("@annotation(com.sugo.seckill.aop.redis.ServiceRedisLock)")
    public void lockAspect(){
    }
    // 增强方法
    @Around("lockAspect()")
    public Object around(ProceedingJoinPoint joinPoint){
        Object obj = null;
        // 加锁
        boolean res = RedissLockUtil.tryLock(Constants.DISTRIBUTED_REDIS_LOCK_KEY,
                TimeUnit.SECONDS, 3,
                10);
        // 执行业务
        try {
            if(res){
                obj = joinPoint.proceed();
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        } finally {
            // 释放锁
            if(res){
                RedissLockUtil.unlock(Constants.DISTRIBUTED_REDIS_LOCK_KEY);
            }
        }
        return obj;
    }
}
public class RedissLockUtil {
    private static RedissonClient redissonClient;
    
    public void setRedissonClient(RedissonClient locker) {
      redissonClient = locker;
    }
    
    /**
     * 加锁
     * @param lockKey
     * @return
     */
    public static RLock lock(String lockKey) {
      RLock lock = redissonClient.getLock(lockKey);
      lock.lock();
        return lock;
    }
    /**
     * 释放锁
     * @param lockKey
     */
    public static void unlock(String lockKey) {
      RLock lock = redissonClient.getLock(lockKey);
    lock.unlock();
    }
    
    /**
     * 释放锁
     * @param lock
     */
    public static void unlock(RLock lock) {
      lock.unlock();
    }
    /**
     * 带超时的锁
     * @param lockKey
     * @param timeout 超时时间   单位:秒
     */
    public static RLock lock(String lockKey, int timeout) {
      RLock lock = redissonClient.getLock(lockKey);
    lock.lock(timeout, TimeUnit.SECONDS);
    return lock;
    }
    
    /**
     * 带超时的锁
     * @param lockKey
     * @param unit 时间单位
     * @param timeout 超时时间
     */
    public static RLock lock(String lockKey, TimeUnit unit ,int timeout) {
      RLock lock = redissonClient.getLock(lockKey);
    lock.lock(timeout, unit);
    return lock;
    }
    
    /**
     * 尝试获取锁
     * @param lockKey
     * @param waitTime 最多等待时间
     * @param leaseTime 上锁后自动释放锁时间
     * @return
     */
    public static boolean tryLock(String lockKey, int waitTime, int leaseTime) {
        RLock lock = redissonClient.getLock(lockKey);
    try {
      return lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
      return false;
    }
    }
    
    /**
     * 尝试获取锁
     * @param lockKey
     * @param unit 时间单位
     * @param waitTime 最多等待时间
     * @param leaseTime 上锁后自动释放锁时间
     * @return
     */
    public static boolean tryLock(String lockKey, TimeUnit unit, int waitTime, int leaseTime) {
      RLock lock = redissonClient.getLock(lockKey);
    try {
      return lock.tryLock(waitTime, leaseTime, unit);
    } catch (InterruptedException e) {
      return false;
    }
    }
    /**
     * 初始红包数量
     * @param key
     * @param count
     */
    public void initCount(String key,int count) {
        RMapCache<String, Integer> mapCache = redissonClient.getMapCache("skill");
        mapCache.putIfAbsent(key,count,3,TimeUnit.DAYS);
    }
    /**
     * 递增
     * @param key
     * @param delta 要增加几(大于0)
     * @return
     */
    public int incr(String key, int delta) {
        RMapCache<String, Integer> mapCache = redissonClient.getMapCache("skill");
        if (delta < 0) {
            throw new RuntimeException("递增因子必须大于0");
        }
        return  mapCache.addAndGet(key, 1);//加1并获取计算后的值
    }
    /**
     * 递减
     * @param key 键
     * @param delta 要减少几(小于0)
     * @return
     */
    public int decr(String key, int delta) {
        RMapCache<String, Integer> mapCache = redissonClient.getMapCache("skill");
        if (delta < 0) {
            throw new RuntimeException("递减因子必须大于0");
        }
        return mapCache.addAndGet(key, -delta);//加1并获取计算后的值
    }
}

基于Zookeeper实现分布式锁

依赖

<dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.14</version>
        </dependency>

定义ZkLock

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;
@Slf4j
public class ZkLock implements AutoCloseable, Watcher {
    private ZooKeeper zooKeeper;
    private String znode;
    public ZkLock() throws IOException {
        this.zooKeeper = new ZooKeeper("localhost:2181",
                10000,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_00000001
            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 close() throws Exception {
        zooKeeper.delete(znode,-1);
        zooKeeper.close();
        log.info("我已经释放了锁!");
    }
    @Override
    public void process(WatchedEvent event) {
        if (event.getType() == Event.EventType.NodeDeleted){
            synchronized (this){
                notify();
            }
        }
    }
}

使用ZkLock

@RestController
@Slf4j
public class ZookeeperController {
    @Autowired
    private CuratorFramework client;
    @RequestMapping("zkLock")
    public String zookeeperLock(){
        log.info("我进入了方法!");
        try (ZkLock zkLock = new ZkLock()) {
            if (zkLock.getLock("order")){
                log.info("我获得了锁");
                Thread.sleep(10000);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info("方法执行完成!");
        return "方法执行完成!";
    }
}

基于curator实现分布式锁

依赖

<dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>4.2.0</version>
        </dependency>

启动类注入CuratorFramework

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

使用

@RestController
@Slf4j
public class ZookeeperController {
    @Autowired
    private CuratorFramework client;
    @RequestMapping("curatorLock")
    public String curatorLock(){
        log.info("我进入了方法!");
        // /order表示业务路径
        InterProcessMutex lock = new InterProcessMutex(client, "/order");
        try{
            if (lock.acquire(30, TimeUnit.SECONDS)){
                log.info("我获得了锁!!");
                Thread.sleep(10000);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                log.info("我释放了锁!!");
                lock.release();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        log.info("方法执行完成!");
        return "方法执行完成!";
    }
}

基于Redisson实现分布式锁(SpringBoot项目推荐用法)

依赖

<dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>3.17.2</version>
        </dependency>

配置redis

使用

@RestController
@Slf4j
public class RedissonLockController {
    @Autowired
    private RedissonClient redisson;
    @RequestMapping("redissonLock")
    public String redissonLock() {
        RLock rLock = redisson.getLock("order");
        log.info("我进入了方法!!");
        try {
            rLock.lock(30, TimeUnit.SECONDS);
            log.info("我获得了锁!!!");
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            log.info("我释放了锁!!");
            rLock.unlock();
        }
        log.info("方法执行完成!!");
        return "方法执行完成!!";
    }
}

基于Redisson实现分布式锁(通过xml配置)

依赖

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

定义redisson.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:redisson="http://redisson.org/schema/redisson"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://redisson.org/schema/redisson
       http://redisson.org/schema/redisson/redisson.xsd
">
    <redisson:client>
        <!--单机模式-->
        <redisson:single-server address="redis://127.0.0.1:6379"/>
    </redisson:client>
</beans>

启动类上添加@ImportResource(“classpath*:redisson.xml”)

@SpringBootApplication
@ImportResource("classpath*:redisson.xml")
public class RedissonLockApplication {
    public static void main(String[] args) {
        SpringApplication.run(RedissonLockApplication.class, args);
    }
}

使用

@RestController
@Slf4j
public class RedissonLockController {
    @Autowired
    private RedissonClient redisson;
    @RequestMapping("redissonLock")
    public String redissonLock() {
        RLock rLock = redisson.getLock("order");
        log.info("我进入了方法!!");
        try {
            rLock.lock(30, TimeUnit.SECONDS);
            log.info("我获得了锁!!!");
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            log.info("我释放了锁!!");
            rLock.unlock();
        }
        log.info("方法执行完成!!");
        return "方法执行完成!!";
    }
}

多种分布式锁,我如何选择

推荐使用Redisson和Cutator实现分布式锁, 成熟,有大量的实践!

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
2月前
|
Java 数据库
在Java中使用Seata框架实现分布式事务的详细步骤
通过以上步骤,利用 Seata 框架可以实现较为简单的分布式事务处理。在实际应用中,还需要根据具体业务需求进行更详细的配置和处理。同时,要注意处理各种异常情况,以确保分布式事务的正确执行。
|
2月前
|
消息中间件 Java Kafka
在Java中实现分布式事务的常用框架和方法
总之,选择合适的分布式事务框架和方法需要综合考虑业务需求、性能、复杂度等因素。不同的框架和方法都有其特点和适用场景,需要根据具体情况进行评估和选择。同时,随着技术的不断发展,分布式事务的解决方案也在不断更新和完善,以更好地满足业务的需求。你还可以进一步深入研究和了解这些框架和方法,以便在实际应用中更好地实现分布式事务管理。
|
16天前
|
Java Maven
java项目中jar启动执行日志报错:no main manifest attribute, in /www/wwwroot/snow-server/z-server.jar-jar打包的大小明显小于正常大小如何解决
在Java项目中,启动jar包时遇到“no main manifest attribute”错误,且打包大小明显偏小。常见原因包括:1) Maven配置中跳过主程序打包;2) 缺少Manifest文件或Main-Class属性。解决方案如下:
java项目中jar启动执行日志报错:no main manifest attribute, in /www/wwwroot/snow-server/z-server.jar-jar打包的大小明显小于正常大小如何解决
|
12天前
|
存储 Java BI
java怎么统计每个项目下的每个类别的数据
通过本文,我们详细介绍了如何在Java中统计每个项目下的每个类别的数据,包括数据模型设计、数据存储和统计方法。通过定义 `Category`和 `Project`类,并使用 `ProjectManager`类进行管理,可以轻松实现项目和类别的数据统计。希望本文能够帮助您理解和实现类似的统计需求。
55 17
|
1月前
|
NoSQL Java 关系型数据库
Liunx部署java项目Tomcat、Redis、Mysql教程
本文详细介绍了如何在 Linux 服务器上安装和配置 Tomcat、MySQL 和 Redis,并部署 Java 项目。通过这些步骤,您可以搭建一个高效稳定的 Java 应用运行环境。希望本文能为您在实际操作中提供有价值的参考。
138 26
|
30天前
|
NoSQL Java Redis
秒杀抢购场景下实战JVM级别锁与分布式锁
在电商系统中,秒杀抢购活动是一种常见的营销手段。它通过设定极低的价格和有限的商品数量,吸引大量用户在特定时间点抢购,从而迅速增加销量、提升品牌曝光度和用户活跃度。然而,这种活动也对系统的性能和稳定性提出了极高的要求。特别是在秒杀开始的瞬间,系统需要处理海量的并发请求,同时确保数据的准确性和一致性。 为了解决这些问题,系统开发者们引入了锁机制。锁机制是一种用于控制对共享资源的并发访问的技术,它能够确保在同一时间只有一个进程或线程能够操作某个资源,从而避免数据不一致或冲突。在秒杀抢购场景下,锁机制显得尤为重要,它能够保证商品库存的扣减操作是原子性的,避免出现超卖或数据不一致的情况。
58 10
|
2月前
|
XML Java 测试技术
从零开始学 Maven:简化 Java 项目的构建与管理
Maven 是一个由 Apache 软件基金会开发的项目管理和构建自动化工具。它主要用在 Java 项目中,但也可以用于其他类型的项目。
70 1
从零开始学 Maven:简化 Java 项目的构建与管理
|
2月前
|
存储 运维 NoSQL
分布式读写锁的奥义:上古世代 ZooKeeper 的进击
本文作者将介绍女娲对社区 ZooKeeper 在分布式读写锁实践细节上的思考,希望帮助大家理解分布式读写锁背后的原理。
|
2月前
|
缓存 Java
java中的公平锁、非公平锁、可重入锁、递归锁、自旋锁、独占锁和共享锁
本文介绍了几种常见的锁机制,包括公平锁与非公平锁、可重入锁与不可重入锁、自旋锁以及读写锁和互斥锁。公平锁按申请顺序分配锁,而非公平锁允许插队。可重入锁允许线程多次获取同一锁,避免死锁。自旋锁通过循环尝试获取锁,减少上下文切换开销。读写锁区分读锁和写锁,提高并发性能。文章还提供了相关代码示例,帮助理解这些锁的实现和使用场景。
java中的公平锁、非公平锁、可重入锁、递归锁、自旋锁、独占锁和共享锁
|
2月前
|
Java
Java项目中高精度数值计算:为何BigDecimal优于Double
在Java项目开发中,涉及金额计算、面积计算等高精度数值操作时,应选择 `BigDecimal` 而非 `Double`。`BigDecimal` 提供任意精度的小数运算、多种舍入模式和良好的可读性,确保计算结果的准确性和可靠性。例如,在金额计算中,`BigDecimal` 可以精确到小数点后两位,而 `Double` 可能因精度问题导致结果不准确。