目录
Reentrantlock和Synchornizedlock
闲聊扯皮部分(可跳过)
最近真是泪目了呀,家人们。就博客好久都没更新了,这不是没有原因的。博主今年不是应届毕业生嘛,就去参加秋招。之前整个8月份都一直在实习,等到八月底,结果没hc了,像猛然惊醒的梦中人一样,就慌不择路地开始投简历,九月初,真的有点迟了呀家人们,不过面试机会还是有一些的,但就是之前没准备啊,光幻想实习转正了,结果就各种挂,然后投了好多要笔试的,笔试又是狂挂。没办法呀,在家闭关学习了一阵子,hc又被卷走了一大批,好容易后来能进面试了,一轮游。本来学的客户端,但人家客户端宁可要零基础算法好的,也不要客户端方向学了学的不精通的,就这样,后来测试也投,通用开发也投……然后银行网申过了,就去做银行笔试,把互联网的一些笔试面试邀约都推了,在这里,真诚的对捞我的互联网公司说一句对不起!然后银行面试人家基本就问后台知识,等于我彻底脱坑了,唉,Java后端好多我也不会呀,各种心酸。。。
什么是锁?
锁,锁住了什么?它锁住的其实是一段同步代码块,这样每次只有一个线程能够进入,防止多个线程同时对共享变量进行操作,防止出现数据不一致的情况。锁,就是并发控制的一种手段。锁保障了线程安全,但换一个角度,能保护线程安全的方式其实不仅仅是锁,至少还有以下几种——
1.不跨线程共享变量,线程共享的变量改为方法局部级变量
2.使状态变量为不可变的,使用final进行修饰
3.在任何访问状态变量的时候使用同步,使用sychornized修饰方法,或使用同步代码块
4.每个共享的可变变量由唯一一个确定的锁保护,使用lock锁。
磨人的锁机制
知道我为什么连夜来更新这篇文章吗?因为今天面试被问到了锁机制。
1.1公平锁与非公平锁
公平锁:多个线程按照申请锁的顺序来获取锁
非公平锁:是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁,有可能出现饥饿和优先级反转。非公平锁的优点在于吞吐量比公平锁大。
1.2乐观锁与悲观锁
乐观锁可以使用volatile+CAS原语实现,带参数版本来避免ABA问题,在读取和替换的时候进行判定版本是否一致。
悲观锁可以使用synchronize的以及Lock。
悲观锁:对外界的修改持保守态度,在整个数据处理中,将数据处于锁定状态,悲观锁适用于读少写多的情况
乐观锁:和悲观锁相反,假设一般情况下不会出现数据冲突的情况,只有在数字进行提交更新时,才会对数据冲突与否进行检测,如果发现冲突了,则返回错误信息,让用户自行处理。一共分为三个阶段:数据读取,写入校验,写入数据。乐观锁适用于读多写少的情况
1.3自旋锁
是采用当前线程不断地在循环体内执行,当循环的条件被其他线程改变时才能进入临界区,自旋锁只是将当前线程不停的执行循环体,不进行线程状态的改变,所以响应速度更快。但当线程数不断增加时,性能会下降明显,因为每个线程都需要执行,会占用CPU时间片,如果线程竞争不激烈,并且保持锁的阶段,适合使用自旋锁。
1.4独享锁和共享锁
ReentrantReadWriteLock,其读锁是共享锁,写锁是独享锁。读锁的共享锁可以保证并发读的高效,读写,写读,写写是互斥的,独享锁和共享锁也是通过AQS来实现的,通过实现不同的方法,来实现独享或共享
独享锁:该锁一次只能被一个线程所持有
共享锁:该锁可被多个线程所持有
锁的四种级别
锁有四种级别,从轻到重分别为无锁,偏向锁,轻量锁,重量锁,每个对象一开始都是无锁的,随着线程间争夺锁越来越激烈,锁的级别也越来越高。
偏向锁:在实际运行的过程中发现,“锁总是一个线程持有,很少发生竞争”,也就是说锁总是被第一个占用他的线程拥有,这个线程就是锁的偏向线程。引入偏向锁是为了在无多线程竞争的情况下尽量减少不必要的轻量级锁执行路径,因为轻量级锁的获取及释放依赖多次CAS指令,而偏向锁只需要在置换ThreadID的时候依赖一次CAS原子指令。当只有一个线程去竞争锁的时候,我们不需要阻塞和自旋。
轻量锁:与偏向锁的区别是每次退出同步块都需要释放锁,而偏向锁是发生竞争时才释放锁;每次进入退出同步块都需要CAS更新同步头,争夺轻量级锁失败时,自旋尝试抢占锁。可以看到轻量锁适合在竞争情况下用,其自旋锁可保证响应速度快,但自旋操作会占用CPU,所以一些计算时间长的操作不适合使用轻量级锁。
重量锁:内置锁在java中被抽象为监视器锁,在JDK1.6之前,监视器锁可以认为直接对应底层操作系统的互斥量,这种互斥的成本非常高,包括系统调用引起的内核态与用户态的切换,线程阻塞造成的线程切换等,后来就被称为重量锁。
什么叫“可重入”锁
可重入就是说某个线程已经获得某个锁,可以再次获取锁而不会出现死锁。所谓可重入,意味着线程可以进入它已经拥有的锁的同步代码块儿。
Reentrantlock和Synchornizedlock
reentrantlock和synchornizedlock都是可重入锁,同一个线程可多次获得同一个锁,都保证了可重入性和互斥性;
reentrantlock和synchornizedlock的区别在于:reentrantlock是显式地获得,释放锁,synchornizedlock隐式的获取释放锁; reentrantlock可响应中断,synchornizedlock不可以,为处理锁的不可用性提供了更高的灵活性;reentrantlock是API级别的,synchornizedlock是JVM级别的。