java中的各种锁总结(简单全面版)

2022-08-11 11:28:12

首先上一张图

是不是吓一跳,下面我们来一项一项说明各种锁的概念以及使用

1.乐观锁

乐观锁顾名思义就是一种乐观的思想,认为读数据时没有别的线程进行过修改,所以不会上锁,写数据时判断当前与期望的值是否相同,如果相同进行更新(更新期间是要枷锁的,为了保证原子性)

举例:java中的乐观锁---CAS

                CAS的使用以及CAS原子操作面临的问题,以及解决方案

                CAS的详细内容请参考

多线程常见面试题总结(简单版)_Mr.米斯特儿赵的博客-CSDN博客  第17个回答

2.悲观锁

   悲观锁顾名思义就是一种悲观的思想,每次拿数据都会悲观的认为其他线程修改了数据,所以每次读写时都会上锁,其他线程想要读写这个数据时,就会被该线程阻塞 ,直到这个线程释放锁.

举例: java中的悲观锁synchronized修饰的方法和方法块  比如我们尝试用的hashtable,以及StringBuffer他们的方法都被synchronized修饰,ReentrantLock不仅悲观还重入(也属于重入锁)

3.自旋锁

自旋锁就是在获取锁的时候,如果锁被其他线程获取,该线程就会一直循环等待,一直尝试着去获取锁,直到目标达成。而不像普通的锁那样,如果获取不到锁就进入阻塞

自旋锁的优点:避免了线程切换的开销,不会使线程进入阻塞的状态,减少了不必要的上下文的切换,执行速度块

自旋锁的缺点:长时间占用处理器,会白白消耗 处理器资源,却没有干任何事情,性能浪费

                        所以自旋等待的时间必须有一定的限度 超过限度就挂起 线程

自旋默认的次数:10次

4.可重入锁(递归锁)

可重入锁使一种技术,任意线程在获取到 锁之后能够再次 获取 该锁而不会被锁阻塞

原理 : 通过组合自定义同步器来实现锁的获取和释放

                再次获取锁: 识别获取 锁的线程是否为当前占据锁的线程,如果是,则再次成功获取,获取锁后,进行计数自增

                释放锁:  释放锁 进行计数自减

java中的可重入锁:

                ReentrantLock、synchronized修饰的方法或代码段

5.读写锁

读写锁使一种技术,通过ReentrantReadWriteLock类来实现的,为了提高性能,Java提供了读写锁,读的地方使用 读锁,写的地方使用写锁,在没有写锁的情况下,读锁是无阻塞的,多个读锁不互斥,读锁与写锁互斥,这是由jvm来控制的

读锁:        允许线程获取读锁,同时访问一个资源

写锁:        允许一个线程获取 写锁,不允许 同时访问一个资源

如何使用:        1.创建一个读写锁

                                ReentrantReadWriteLock rwLock =newReentrantReadWriteLock();

                        2.获取读锁和释放锁

//获取读锁rwLock.readLock().lock();//释放读锁rwLock.readLock().unlock();

                        3.获取写锁和释放锁

创建一个写锁rwLock.writeLock().lock();//写锁 释rwLock.writeLock().unlock()

6.公平锁

        公平锁使一种思想,多个线程按照顺序来获取锁 ,并发环境中,每个线程会去查看锁的维护队列,如果队列为空,就占有锁,如果队列不为空,就加入等待队列的末尾,按照FIFO原则获取锁

7.非公平锁

        非公平锁也是一种思想,线程尝试获取锁,如果获取不到,按照公平锁的方式,多个线程获取锁不是按照 先到先得的顺序.是无序的,有可能后到了先获取到锁

        优点:        比公平锁性能高

        缺点:        线程 饥饿(某个线程很长一段时间获取不到锁)

        举例:        synchronized是非公平锁

ReentrantLock通过构造函数指定该锁是公平的还是非公平的,默认是非公平的。

8.共享锁

共享锁是一种思想,可以多个线程获取读锁,以共享的方式持有锁,和乐观锁还有读写锁同义

9.独占锁

 独占锁是一种思想,只能有一个线程获取锁,以独有的方式持有锁,悲观锁和互斥锁同义

synchronized,ReentrantLock

10.重量级锁

synchronized就是重量级锁,为了优化重量级锁,引入了轻量级锁和偏向锁

11.轻量级锁

   jdk6是加入的一种锁的优化机制,轻量级锁是在没有多线程竞争的情况下使用的CAS操作去消除同步使用的互斥量

        上面理解起来很吃力,解析一下,首先是没有竞争,也就是说是单线程,两条以上线程,轻量级锁不会生效

12.偏向锁

偏向锁是JDK6时加入的一种锁优化机制:在无竞争的情况下把整个同步都消除掉,连CAS操作都不去做了。偏是指偏心,它的意思是这个锁会偏向于第一个获得它的线程,如果在接下来的执行过程中,该锁一直没有被其他的线程获取,则持有偏向锁的线程将永远不需要再进行同步。持有偏向锁的线程以后每次进入这个锁相关的同步块时,虚拟机都可以不再进行任何同步操作.

13.分段锁

 是一种机制,是不是想到了ConcurrentHashMap了,默认情况下ConcurrentHashMap被细分为16个段(Segment)每次上锁只是锁的每个segment. segment通过继承ReentrntLock来进行加锁,只要保证每个segment是线程安全的,是不是就保证了全局的线程安全.

14.互斥锁

互斥锁和悲观锁还有独占锁同义,某个资源,只能被一个线程访问,其他线程不能访问.

例如上文提到的读写锁中的写锁,写与写之间是互斥的,写与读之间也是互斥的

15.同步锁

与互斥锁同义,字并发执行多个线程时,在同一时间只允许一个线程访问共享数据synchronized

16.死锁

死锁是一种现象:如线程A持有资源x,线程B持有资源y,线程A等待线程B释放资源
y,线程B等待线程A释放资源x,两个线程都不释放自己持有的资源,则两个线程都获
取不到对方的资源,就会造成死锁。
Java中的死锁不能自行打破,所以线程死锁后,线程不能进行响应。所以一定要注意
程序的并发场景,避免造成死锁。

17.synchronized(简单总结)

synchronized是java中的关键字,用来修饰方法,对象实例,属于独占锁,悲观锁,可重入锁,非公平锁

        用于实例方法时,锁住的是对象的实例也就是this

        用于静态方法上,锁主的是Class类

18.Lock和synchronized的区别

lock  是java中的接口,是可重入锁,悲观锁,独占锁,互斥锁,同步锁

lock 需要手动获取锁和释放锁

        lock 是一个接口,synchronized是关键字

        synchronized发生异常会自动释放锁,不会导致死锁现象,而lock发生异常如果没有unlock()释放锁,就有可能产生死锁,一般使用lock锁的时候,需要在finally中进行释放锁

        lock锁可以使等待的线程响应中断,而synchronized不会,会一直等待下去

19.ReentrantLock 和synchronized的区别

Reentrantlock是java中的类,继承了lock类,是可重入锁,悲观锁,独占锁,互斥锁,同步锁

相同点:        主要解决共享变量如何访问的问题

                     都是可重入锁,同一线程可以多次获取锁

                     保证了线程安全的两大特性   可见性   原子性

不同点:

  1. ReentrantLock 就像手动汽车,需要显示的调用lock和unlock方法,synchronized 隐式获得释放锁。
  2. ReentrantLock 可响应中断, synchronized 是不可以响应中断的ReentrantLock 为处理锁的不可用性提供了更高的灵活性
  3. ReentrantLock 是 API 级别的, synchronized 是 JVM 级别的
  4. ReentrantLock 可以实现公平锁、非公平锁,默认非公平锁,synchronized 是非公平锁,且不可更改。
  5. ReentrantLock 通过 Condition 可以绑定多个条件
  • 作者:Mr.米斯特儿赵
  • 原文链接:https://blog.csdn.net/weixin_60272582/article/details/123265596
    更新时间:2022-08-11 11:28:12