锁策略与synchronized
文章目录锁的策略1. 乐观锁与悲观锁2. 轻量级锁和重量级锁3.自旋锁和挂起等待锁4.普通互斥锁和读写锁5.公平锁和非公平锁6.可重入锁和不可重入锁synchronized内部优化手段偏向锁-轻量级锁-重量级锁1.偏向锁阶段2.轻量级锁阶段3.重量级锁阶段锁消除锁粗化多线程中加锁还可以细致的分情况以下是各种锁的概念了解以针对面试锁的策略加锁过程中处理冲突的不同处理方式并非JAVA独有。1. 乐观锁与悲观锁乐观锁 在加锁之前预估当前锁发生冲突的概率不大就不需要太多准备工作。加锁的过程中工作少了速度会更快但是容易引发一些问题。悲观锁 在加锁之前预估当前锁发生的冲突比较大需要有很多准备工作。速度略慢但是更安全。2. 轻量级锁和重量级锁轻量级锁加锁的开销小加锁的速度更快重量级锁 加锁的开销大加锁的速度慢乐观锁和轻量级锁的区别在于 乐观锁是在加锁之前对开销的预估而轻量级锁是加锁之后对加锁结果的评价。悲观锁和重量级锁同理。3.自旋锁和挂起等待锁自旋锁通过while(true)等方式一直快速循环等待加锁,如果没有加上,那就再循环,直到拿到锁之后,循环停止. 这种方式加锁消耗的时间短,但是会消耗更多的CPU. 因此,自旋锁也是乐观锁,预计发生的冲突不大. 相反,如果有很多复杂的线程以自旋锁的方式抢占锁,则会非常浪费CPU资源.挂起等待锁: 如果等不到加锁,那就阻塞等待,等待系统的调度,啥时候调度到时未知的. 这种方式不占用CPU. 但是速度相比更慢. 是一种悲观锁.实现JVM的大佬们已经为我们配置高了synchronized.synchronized是一种自适应锁:如果加锁容易发生冲突,synchronized就是乐观锁/轻量级锁/自旋锁;如果加锁不容易发生冲突,synchronize就是悲观锁/重量级锁/挂起等待锁.4.普通互斥锁和读写锁普通互斥锁就是考虑加锁和解锁的情况与synchronized的使用类似读写锁将锁分为了读锁和写锁具体可分为以下情况:读锁和读锁之间不会阻塞写锁和写锁之间阻塞读锁和写锁之间阻塞读操作根本就不会引发线程安全问题,为什么还要进行加锁?可以借鉴这篇博客介绍了脏读不可重复读和幻读,在隔离性总结.就是写的时候需要加锁,而正在读的过程中也不能直接修改掉内容,不然会给用户造成极差体验,也需要给读进行加锁.synchronized要想给读加锁,就会在读与读之间发生阻塞,浪费了性能,所以引入读写锁解决这种情况.5.公平锁和非公平锁怎么样是公平的定义是开发大佬决定的,不必纠结公平锁: 加锁遵循先来后到,先来的线程能先拿到锁非公平锁不遵循先来后到系统原生的锁是非公平的,因为线程的调度本来就是随机的,没有按顺序排列.要想实现公平锁,就要引入额外的数据结构,引入队列来记录线程的先后顺序. 公平锁可以解决线程饿死问题.6.可重入锁和不可重入锁可重入锁ThreadtnewThread(()-{synchronized(locker){synchronized(locker){System.out.println(hello);}}});在java中 同一个线程在已经对实例加锁之后继续加锁第二次锁不会进入使线程阻塞可重入锁内部会持有两个信息1是加锁次数的计数器2是这个锁被哪个线程所占有。这种特殊的情况最重要的一点就是它是在同一个线程中执行的。同一线程中就仅仅做计数器的操作。而这种操作实际上没有什么意义是代码冗杂。在其他语言中会存在不可重入锁不可重入锁在同一线程多次加锁就会阻塞。synchronized内部优化手段偏向锁-轻量级锁-重量级锁synchronized与系统原生锁对比特性JavasynchronizedLinuxmutex(原生锁)乐观锁/悲观锁自适应可升级为悲观锁悲观锁锁级别轻量级锁/重量级锁自适应重量级锁等待方式自旋锁/挂起等待锁自适应挂起等待锁读写锁不是读写锁互斥锁不是读写锁互斥锁公平性非公平锁非公平锁可重入性可重入锁不可重入锁1.偏向锁阶段在没有其他线程抢占锁的时候,还没有释放锁,就先进行标记(轻量高效),等到锁释放之后,就可以快速的加锁,省去了一定的时间开销.(注意!偏向锁一定是没有其他线程竞争下才会发生,一旦有其他线程竞争就会退出偏向锁.)2.轻量级锁阶段一旦有线程进行竞争(少数的线程竞争),就会进入自旋锁阶段,可以第一时间拿到锁,但比较消耗CPU.会记录当前有多少线程在竞争锁,一旦越过了某个数量(JVMt调配),就会升级成重量级锁.3.重量级锁阶段有大量的线程竞争锁,此时自旋锁会极大浪费CPU资源,因此锁不再自旋,改为阻塞等待锁消除当synchronized加锁囊括了一些不会引发线程安全的内容,例如局部变量(线程之间是无法互相传递使用局部变量的),编译时synchronized就会智能的将这些内容移除出加锁. 然而,锁消除也并不是完全智能的,一些模棱两可的数据是不会移除的锁粗化将多个加锁过程连接起来,变成一次加锁.通常情况下,锁是越细越有利于并发执行,但是如果频繁的加锁解锁加锁解锁,有加锁解锁,就会有阻塞.那效率会变得低.于是将多段加锁和为一段,就可以减少锁竞争的开销.