当前位置: 首页 > article >正文

【spring】spring单例模式与锁对象作用域的分析

前言:spring默认是单例模式,这句话大家应该都不陌生;因为绝大多数都是使用单例模式,避免了某些问题,可能导致对某些场景缺乏思考。本文通过结合lock锁将单例模式、静态变量、锁对象等知识点串联起来。

文章目录

  • synchronized与ReentrantLock
  • 静态变量
  • spring与ReentrantLock整合
  • 生产环境项目加锁方案

synchronized与ReentrantLock

这两种锁,提得最多的两点区别:
1.效率问题
2. ReentrantLock可以设置超时时间

当然,还有其它区别 例如ReentrantLock支持公平锁 本文不展开重点讨论,本文重点从第一点延伸。

关于效率问题,主要是旧版jdk6之前 锁很重 ,在jdk6之后优化了很多;可能有同学会说synchronized锁的范围太大了,ReentrantLock锁的范围小,但其实只要我们自己定义一个锁对象即可:

Object lock = new Object();

public void test(){
 // do something
 synchronized(lock){
   // do something
 }
 // do other
}

从上面代码我们可以看到有个重要的概念:锁对象,通俗点理解就是根据什么对象来判断是否加上了锁。

再看看ReentrantLock的写法:

ReentrantLock lock = new ReentrantLock();

public void test(){
	// do something
	lock.lock();
	// do other
	lock.unlock();
}

不难发现,ReentrantLock并没有显式的声明锁对象;其实就是lock对象本身,锁的是它自己。

正因为lock.lock() 是锁它本身,所以我们需要思考,当lock对象发生了变化,锁是否还能达到我们的预期。

静态变量

简单复习一下:静态变量存放于jvm的方法区,它只会执行一次,是共享变量。

spring与ReentrantLock整合

我们假设业务场景为:同一时刻 只允许一个用户下单,且为单体项目(即不考虑集群多实例)

简单看一下demo代码:思考从前端/浏览器发起多次请求,打印结果是否一致?

@RestController
@RequestMapping("/test/single")
public class SingleController {
    private Lock lock  = new ReentrantLock();
    @GetMapping
    public void test() {
        System.out.println(lock.hashCode());
    }
}

答案是一致,因为spring默认是单例模式,所以每次访问的SingleController bean ,都为同一个,bean没重新创建,里面的属性(demo中的lock对象)自然也都是同一个。

如果实在担心hashCode不严谨,或者可能是hash碰撞问题,那我们可以加锁,看多次请求浏览器是不是在等待响应也可以得到相应的结论。

如下代码,超时时间设为10秒
在这里插入图片描述

观察浏览器后续请求是否在等待响应(等待锁释放)
在这里插入图片描述

我们再来看看反面教材:

@RestController
@RequestMapping("/test/single")
public class SingleController {
    @GetMapping
    public void test() {
        Lock lock  = new ReentrantLock();
        lock.lock();
        System.out.println("下单---");
        // 省略try catch finally
        lock.unlock();
    }
}

这把锁有作用吗?答案是否定的,因为每次进入到方法里面,生成的都是新对象,锁对象也都变了。


习惯了spring的单例模式,那接下来我们再手动把spring的模式改成多例会发生什么呢:
@RestController
@RequestMapping("/test/single")
@Scope("prototype")
public class SingleController {
    private Lock lock  = new ReentrantLock();

    @GetMapping
    public void test() {
        System.out.println(lock.hashCode());
    }
}

这把锁还有用吗?答案是否定的,因为每次浏览器发起请求,SingleController 是不同的对象,那lock自然也是不同的对象,所以失去了锁的作用。

那么如果在多例模式下,还想锁生效该怎么办呢?前文提到了静态变量的概念,静态变量初始化后就不会改变(除非我们手动改),那只要将锁对象修饰为static,即可达到效果:

@RestController
@RequestMapping("/test/single")
@Scope("prototype")
public class SingleController {
    private static Lock lock  = new ReentrantLock();

    @GetMapping
    public void test() {
        System.out.println(lock.hashCode());
    }
}

本文通过一个简单的案例,将锁对象和spring单多例知识点串联,巩固java基础。

生产环境项目加锁方案

在实际的企业项目中,都会集群部署,所以我们需要引入分布式锁,如redis锁,可以基于数据量考虑手写redis锁,或引入redisson;具体案例分析可以在博主首页搜索“超卖”


http://www.kler.cn/a/405151.html

相关文章:

  • FreeRTOS之vTaskDelete实现分析
  • C++ 中的移动语义
  • 区块链网络示意图;Aura共识和Grandpa共识(BFT共识)
  • WebApis学习笔记,第二节:高级语法
  • ant-design-vue中table组件多列排序
  • WebStorm 安装配置(详细教程)
  • 【IOS】Undefined symbol: _OBJC_CLASS_$_PAGFile
  • Java通过calcite实时读取kafka中的数据
  • 学习threejs,通过SkinnedMesh来创建骨骼和蒙皮动画
  • WSL2 ubuntu配置redis
  • Simulink学习笔记【PID UG联动仿真】
  • 算法.图论-习题全集(Updating)
  • 【Android、IOS、Flutter、鸿蒙、ReactNative 】自定义View
  • 力扣 LeetCode 513. 找树左下角的值(Day8:二叉树)
  • [服务器] 腾讯云服务器免费体验,成功部署网站
  • PBDL (基于物理的深度学习)-Chapter 1
  • 深度学习day2-Tensor 2
  • 【Git】git从暂存区中移除文件
  • 山泽HDMI切换器:提升家庭娱乐与办公体验的利器
  • 支持向量机SVM——基于分类问题的监督学习算法
  • HBase 原理
  • 蓝桥杯每日真题 - 第19天
  • 第27天 安全开发-PHP应用TP 框架路由访问对象操作内置过滤绕过核心漏洞
  • 生产环境centos8 Red Hat8部署ansible and 一键部署mysql两主两从ansible脚本预告
  • 经验笔记:远端仓库和本地仓库之间的连接(以Gitee为例)
  • 在Sui 区块链上创建、部署和管理 NFT 的完整教程