java开发中锁的一些概念简述

本文详细解析了Java中的各种锁机制,包括排他锁、共享锁、读写锁、自旋锁及其变种、偏向锁、轻量级锁、重量级锁、死锁以及公平锁和非公平锁的概念。此外,还探讨了锁升级、锁降级、锁消除和锁粗化的优化策略。

排他锁(独占锁)

锁独占,使用排他锁 则只能由获取锁的一个线程 执行该语句块,其他线程只能等待锁释放后竞争锁

共享锁

共享锁,能由多个线程同时获取锁,并发执行;(可能会问 多个线程并发执行了还加锁干嘛,例如读锁 和写锁,读锁是共享锁,可以多个线程同时获取锁,读锁是为了排斥写锁,当有线程获取读锁的时候 其他线程不能获取写锁)

读写锁

读锁: 也就是共享锁, 多个线程可以同时获取读锁,当有线程在读数据的时候,其他线程不能写
写锁: 排他锁,线程获取写锁后,其他线程不能读
读读可以多线程并发, 读写 , 写读, 写写 都是 互斥的

自旋锁

自旋锁:是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环;
减少了 线程上下文切换的性能消耗,但是如果某个线程持有锁的时间过长,就会导致其它等待获取锁的线程进入循环等待,消耗CPU。使用不当会造成CPU使用率极高;
如果获取锁自选的时间过长就会一直造成cpu空转,消耗资源,所以,我们需要给自旋加一个限定次数,不能让它这样一直的这样转下去。如果超过了这个次数还没获得就要被挂起,但是很有可能会出现一种问题,就是我们刚刚被挂起的时候占用锁的线程刚好释放了锁(这就是特别的缘分),那这样就非常尴尬了。所以在JDK6的时候有了自适应自旋锁

自适应自旋锁

** 把以前定死的自选次数给变成动态的,让自旋的次数不再是固定的了,而是根据上一次在同一个锁的自旋时间和锁的拥有者来判断。
线程如果自旋成功了,那么下一次自旋的次数会更多,因为我们会认为,既然上次已经等待成功了,那么这次的自旋也很有可能成功,于是会增加自选的次数
线程如果自旋失败了,那么下次这个锁就会对这个锁的自旋次数会减少,如果很多线程获取这个锁都自旋失败了很可能导致线程在下一次可能根本就不会去自旋,直接跳过。以免浪费CPU的资源**

偏向锁

偏向锁 是为了 在线程竞争非常少 或者只有一个线程在获取锁释放锁的时候 造成的加锁释放锁的性能消耗的一种解决办法;为了减少锁的获取和释放的资源浪费。
偏向锁只有初始化时需要一次CAS,如果当前线程获取锁偏向锁后则以后可以零成本直接获取锁,而不用参与锁竞争;如果有其他线程竞争,则会升级为轻量级锁

轻量级锁

采用CAS算法进行数据操作,不会加锁,如果出现线程竞争问题 才加锁升级为重量级锁;
举例:b线程在锁竞争时,发现锁已经被a线程占用,则b线程不进入内核态,让b线程自旋,执行空循环,等待a线程释放锁。如果,完成自旋策略还是发现a线程没有释放锁,或者让c线程占用了。则b线程试图将轻量级锁升级为重量级锁。
优点: 竞争的线程不会阻塞,提高了程序的响应速度
缺点: 如果线程一直竞争不到锁,就会一直存于自旋空执行状态,消耗cpu

重量级锁

内置锁在Java中被抽象为监视器锁(monitor)。在JDK 1.6之前,监视器锁可以认为直接对应底层操作系统中的互斥量(mutex)。这种同步方式的成本非常高,包括系统调用引起的内核态与用户态切换、线程阻塞造成的线程切换等。因此,后来称这种锁为“重量级锁。
举例:synchronized使用的就是内置锁,重量级锁

死锁

死锁是多线程竞争条件下,线程之间互相等待释放锁而造成的线程假死状态,线程一直处于等待状态;
产生死锁的必要条件

  1. 互斥条件;即存在多线程对共享资源的竞争且 在一段时间内某资源仅为一进程所占用
  2. 请求和保持条件: 当线程阻塞时,对获取的资源保持不放
  3. 不剥夺条件: 加锁后资源未使用完毕不释放,不可剥夺,只能时使用完毕后自己释放资源
  4. 环路等待条件: 当发生死锁时,所等待的进程必定会形成一个环路(类似于死循环),造成永久阻塞。
    解决死锁的基本方法
    1. 就是破坏其中的一个或者多个产生死锁的条件
    2. 顺序获取锁
    3. 超时放弃 例如使用 tryLock(long time, TimeUnit unit)
公平锁和非公平锁

公平和非公平锁的队列都基于锁内部维护的一个双向链表,表结点Node的值就是每一个请求当前锁的线程。公平锁则在于每次都是依次从队首取值。非公平锁,线程在等待锁的过程中, 如果有任意新的线程妄图获取锁,都是有很大的几率直接获取到锁的获取锁是随机的 而不是按照队列中的顺序的。

其他
  • 活锁: 线程之间 互相让步,导致的 谁都执行不下去

  • 线程饿死:线程长时间获取不到CPU的执行时间片,而导致的一直不能执行的现象

  • 线程饥饿: 由于线程优先级 或其 出现线程独占资源不释放,其他线程只能一直处于等待阻塞状态

  • 锁消除: 是jvm在编译时对锁进行的一种优化,比如有时候我们写的代码其实不用加锁,却执行了加锁操作 比如时对局部变量的同步加锁操作;
    也就是说对非共享对象上进行同步是无效的,因此runtime可以啥也不做。同步有可能是不需要的,这为优化提供了机会。
    因此,如果逃逸分析发现对象是非逃逸的,编译器就可以自行消除同步。

  • 锁粗化: 通常情况下并发编程中,我们会把锁的力度尽量缩小范围,但是在某些情况下 高频率的加锁和释放锁 会严重影响 性能问题,所以出现了 把多个锁合并成一个 把原来每个小范围的加锁操作 合并成能覆盖到原来各个锁的范围的一个锁,扩大了锁范围 不用频繁的加锁释放锁操作而带来的 性能损耗。
    锁粗化就是告诉我们任何事情都有个度,有些情况下我们反而希望把很多次锁的请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗

  • 锁升级: 例如轻量级锁升级为 重量级锁;或者读锁升级为写锁 ,

  • 锁降级: 写锁降级为读锁,这只是开发中可能会用到的。并不是jvm的锁优化涉及的

### 银行Java开发业务面试问题及答案 #### 多线程与并发编程 对于银行Java开发岗位而言,多线程和并发编程是非常重要的技能之一。理解如何确保代码在线程环境下的安全性至关重要。 - **什么是线程安全?** 线程安全指的是在一个类或程序能够在多线程环境中正常运作而不发生数据不一致或其他异常情况的现象[^2]。为了实现这一点,开发者通常会采用同步机制、原子操作以及不可变对象等方式来保护共享资源免受竞争条件的影响。 - **volatile关键字的作用是什么?** `volatile` 是一种特殊的修饰符,用于声明变量可能会被多个线程异步修改。它保证了每次读取该字段时都会获取最新的值而不是缓存中的旧版本;同时也防止指令重排序优化破坏可见性和有序性约束。 ```java private volatile boolean flag = false; ``` #### 数据库交互与事务管理 银行业务逻辑往往涉及到频繁的数据访问操作,因此候选人应该熟悉SQL查询优化技巧以及ORM框架(如Hibernate)。另外,在处理金融交易时还需要特别注意ACID特性——即原子性、一致性、隔离性和持久性的保障措施。 - **描述一下乐观和悲观的区别及其应用场景。** 悲观定假设冲突发生的概率较大,所以在整个事务期间都保持对记录加状态直到提交完成为止;而乐观定则认为大多数情况下不会有其他进程干扰当前的操作过程,仅当检测到确实存在更新冲突的时候才会采取相应策略进行解决。前者适用于高并发写入场景下减少死风险,后者适合读远大于写的场合提高吞吐量效率。 - **谈谈你对Spring Transaction的理解。** Spring提供了声明式的事务支持功能,通过AOP代理的方式自动控制数据库连接生命周期内的commit/rollback动作。可以基于XML配置文件定义规则也可以利用@Transactional注解简化编码流程。此外还允许自定义PlatformTransactionManager接口的具体实现以便适配不同类型的持久层技术栈需求。 #### JVM调优经验分享 掌握JVM内部工作机制有助于定位并修复性能瓶颈问题,尤其是在大型分布式系统中显得尤为重要。了解垃圾回收算法原理、内存分配策略等方面的知识可以帮助工程师更好地调整参数设置从而获得更佳的应用表现效果。 - **解释Full GC的概念,并列举几种常见的触发原因。** Full GC是指针对老年代空间执行的一次完整的清理活动,这将暂停所有的应用程序线程直至结束。常见诱因包括但不限于:新生代晋升失败导致Promotion Failed事件的发生;永久区满溢出造成Metaspace OOM错误;显式调用了System.gc()方法请求强制收集等情形。 - **简述G1 Garbage Collector的工作方式。** G1是一种分区压缩型GC方案,默认按照固定大小划分Region区域作为基本单位来进行标记清除作业。其核心优势在于能够设定最大停顿时间目标(Maximum Pause Time Goal),并通过预测模型动态规划哪些部分优先整理以满足SLA要求的同时尽可能降低碎片化程度影响后续分配速度。 #### Web容器部署实践指南 最后但同样重要的是关于Web应用服务器的选择与维护方面的话题讨论。像Apache Tomcat这样的开源软件广泛应用于企业级项目当中,所以求职者应当具备一定的安装配置经验和故障排查能力。 - **怎样查看Tomcat的日志信息?** 日志文件一般位于<tomcat_home>/logs目录下面,其中catalina.out包含了启动关闭过程中产生的标准输出流内容;localhost.<date>.log则是各个虚拟主机对应的HTTP请求响应日志;manager.<date>.log专门用来记录管理员界面的相关行为轨迹等等。可以通过命令行工具tail -f实时监控最新变动状况或者借助ELK Stack搭建集中化的日志管理系统便于后期分析审计用途。 ```bash tail -f /path/to/tomcat/logs/catalina.out ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值