锁策略(锁策略的简单介绍以及synchronized的锁策略)

基本的锁策略

1.乐观锁和悲观锁

乐观锁:总是假设好的情况,认为多线程对数据进行更新的时候不会发生冲突,所以不上锁,直接进行操作,在操作过程中,通过“版本号”进行冲突检测,如果没有发生冲突就正常更新数据,如果发生冲突,就需要重新读取数据并重试操作 或者返回错误信息,让用户重新决定如何去做。

悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁。

当线程冲突严重时,就需要加锁,来避免线程频繁访问共享数据失效带来的CPU空转问题。它可以确保数据的正确性,但是会导致性能下降。

当线程冲突不严重的时候,可以采用乐观锁策略来避免多次的加锁解锁操作。它可以提高并发性能,但是需要处理冲突和重试操作,实现方式之一就是CAS。

2.读写锁:

多个线程对数据进行读操作并不会引起冲突

多个线程对数据进行写操作就可能引起冲突

一个线程进行读操作一个进行写操作可能引起冲突

因此,我们将一把锁分为两部分:读锁和写锁,其中读锁允许多个线程同时获得,因为读操作本身是线程安全的,而写锁则是互斥锁,不允许多个线程同时获得写锁,并且写操作和读操作也是互斥的。

读写锁可以提高并发性,适合于读操作频繁的情况。

3.重量级锁和轻量级锁、

锁的核心特性 "原子性", 这样的机制追根溯源是 CPU 这样的硬件设备提供的.

1.CPU 提供了 "原子操作指令".

2.操作系统基于 CPU 的原子指令, 实现了 mutex 互斥锁.

3.JVM 基于操作系统提供的互斥锁, 实现了 synchronized 和 ReentrantLock 等关键字和类.

线程的阻塞是一件“很伤”的事情,一旦线程因为阻塞而陷入挂起等待(因为涉及到内核态,系统啥时候处理你难以揣摩),就不知道啥时候才会被唤醒,影响效率

用户态就像是你去银行用ATM取钱,自己掌握事情发展的进度,内核态就像是你去办理一件复杂的业务需要工作人员来协调处理,需要消耗大量的资源,并且这个时候这个工作人员还有可能被领导拉去谈话,上厕所等等,你只能眼巴巴干等。

重量级锁:

需要操作系统和硬件支持,涉及到大量用户态到内核态的切换,并且可能涉及到线程的切换,线程获取重量级锁失败进入阻塞状态。(mutex锁)

轻量级锁:

尽量在用户态执行操作,线程不阻塞,不会进行状态切换。

一个悲观锁很可能是一个重量级锁,一个乐观锁很可能是一个轻量级锁。

4.自旋锁和挂起等待锁

自旋锁:轻量级锁的一种典型实现,在用户态通过自旋的方式实现加锁(通过while循环不断地尝试获取获取锁)。线程获取锁失败并不会让出CPU线程也不阻塞,不会从用户态切换到内核态,线程在CPU空跑,当锁被释放,此时这个线程很快就会获取到锁。

挂起等待锁:通过内核态,借助系统提供的锁机制,在出现锁冲突时涉及到线程的调用,使出现冲突的线程阻塞等待(挂起)。

自旋锁可以第一时间获得锁,不会进入阻塞状态,可以提高效率,但是如果一直拿不到锁,就会让cpu空转,浪费资源。

5.公平锁和非公平锁

公平锁:遵循先来后到原则,获取锁存在优先级

不公平锁:获取锁时各凭本事,公平竞争,不遵循先来后到原则。

6.可重入锁

synchronized(锁1) {
    synchronized(锁1) {


    }
}

可重入锁在嵌套加锁(同一把锁)时不会产生死锁(如示例代码),不可重入锁在嵌套加锁时会产生死锁。

synchronized时可重入锁

**synchronized的锁策略

1. 开始时是乐观锁, 如果锁冲突频繁, 就转换为悲观锁.

2. 开始是轻量级锁实现, 如果锁被持有的时间较长, 就转换成重量级锁.

3. synchronized的轻量级锁基于自旋锁来实现,重量级锁基于系统的互斥锁来实现

4. 是一种不公平锁

5. 是一种可重入锁

6. 不是读写锁

加锁时编译器产生的优化

1.锁消除

锁消除是一种编译器优化技术,它通过静态分析和代码转换来消除不必要的锁操作,从而提高程序的性能。在Java中,锁操作是比较耗时的操作,因为它需要进行用户态和内核态之间的切换、上下文保存和恢复等操作。如果锁操作不是必须的,那么就会浪费大量的系统资源,影响程序的性能。锁消除就是通过静态分析和代码转换来判断锁操作是否必须,如果不必须就将锁操作删除。

比如,在单线程状态下,系统会自动取消StringBuffer的加锁机制。

2.锁粗化

加锁是一件费时费力的事情,锁粗化就是通过扩大锁的范围来减少锁操作的次数。例如,在某些情况下,程序会对同一个对象进行多次加锁和解锁操作,这会导致大量的锁操作。如果编译器发现这种情况,就可以将多个连续的锁操作合并成一个大的锁操作,从而减少锁操作的次数,提高程序的性能。

举例:

for(很多次) {

加锁{
}
加锁{
}
//此处省略个好多个加锁操作

}

这时系统就会扩大加锁的范围来减少加锁操作

加锁{
for(  ){

}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值