关于锁策略

在Java中对于多线程来说,锁是一种重要且必不可少的东西,那么我们将如何使用以及在什么时候使用什么样的锁呢?请各位往下看

悲观锁VS乐观锁

悲观锁:

在多线程环境中,冲突是非常常见的,所以在执行操作之前,悲观锁就会先把这个资源进行加锁,用来保证数据的一致性和完整性,阻止了其他线程同一时间对这个数据进行修改,但是可能会降低并发性能,因为只有等到锁释放其他线程才能继续执行

乐观锁:

假设数据一般不会产生冲突,所以当数据进行提交更新的时候,才会对这个数据进行检测来查看是否发生了并行冲突,对比与悲观锁来说是一个更轻量级的锁,一般用于读操作更多的时候,当数据冲突较少的时候,乐观锁能极大的提高并发性能

什么时候用乐观锁比较好,什么时候用悲观锁比较好?

当读操作远多于写操作的时候,我们就可以用乐观锁,减少锁的开销,提高并发性能。当多个线程频繁的修改同一份数据的时候,我们就可以使用悲观锁来保证数据的一致性和完整性,避免数据产生冲突。

重量级锁VS轻量级锁

重量级锁:

重量级锁依赖于操作系统层面的互斥量(mutex)来实现,这种锁机制涉及到用户态和内核态之间的切换,开销较大。当一个线程获取重量级锁的时候,这个线程就会独占该锁所保护的资源,当其他线程想要获取这把锁的时候就会被阻塞,直到锁被释放

轻量级锁:

通常依赖于CAS操作来尝试获取锁,在冲突较少的情况下,轻量级锁可以显著的提高并发性能,但是如果多次获取锁失败则可能会变成重量级锁

  • 轻量级锁:使用 CAS 操作尝试获取锁,尽量避免阻塞线程。
  • 重量级锁:涉及到线程的阻塞和挂起,需要操作系统层面的支持,性能开销更大。

自旋锁VS挂起等待锁

自旋锁:

当线程加锁失败后,不会让线程进入阻塞状态,而是在一个循环里面不断获取这把锁,直到拿到为止,但是假如这把锁被持有的时间很长,就会导致CPU资源浪费,因为线程会不断的检查这把锁的状态

挂起等待锁:

当一个线程已经拥有锁了,但是另一个线程尝试获取这个锁时,就无法立刻获得,此时,这个未获取锁的线程就会被挂起并放入等待队列中,直到锁被释放,相比较于自旋锁来说不用频繁的获取锁的状态,挂起等待的时候是不消耗CPU资源的

  • 自旋锁:能第一时间获取到锁,不涉及线程调度和阻塞,但是如果锁持有的时间较长就会消耗大量的CPU
  • 挂起等待锁:挂起等待是不消耗CPU的,适用于数据修改较少的场景,并且挂起等待锁是重量级锁的一个典型特征

公平锁VS非公平锁

什么叫做公平,是先来后到叫做公平还是概率平均叫做公平,其实都是,但是对于公平锁来说遵循先来后到的原则是公平,而非公平锁则是遵循概率均等

公平锁:

当一个线程尝试获取锁的时候,会先检查该锁是否可用,如果可用则获取锁并继续执行,如果不可用则进入等待队列,直到锁被释放,按照进入等待队列的顺序拿到锁并使用

非公平锁:

非公平锁会先检查当前的锁是否可用,如果可用则获取锁并继续执行,如果不可用则可能会忽略等待队列中的线程,并允许当前线程继续获取锁,这就导致了可能某些线程会进行长时间的等待,从而导致“饿死”

可重入锁和不可重入锁

可重入锁:

在Java中,synchronized 这个关键字本身就帮我们实现了可重入锁这个功能,可重入性:同一个线程可以多次获取同一把锁,从而减少了死锁的概率

不可重入锁:

不允许同一个线程多次获取同一把锁,如果一个线程试图再次获取它所持有的锁,此时就会导致死锁

读写锁

读锁:

允许多个线程同时进行读操作,适用于读多写少的场景,提高并发性能

写锁:

只允许一个线程进行读操作,一个线程进行写操作

  • 读加锁和读加锁之间, 不互斥
  • 写加锁和写加锁之间, 互斥
  • 读加锁和写加锁之间, 互斥
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值