searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

锁的分类

2024-07-26 09:57:31
15
0

1. 公平锁和非公平锁

1.1 公平锁

指多个线程按照申请锁的顺序来获取锁,线程直接进入队列中排队,队列中的第一个线程才能获得锁。

优点:等待锁的线程不会饿死。

缺点:整体吞吐效率相对非公平锁要低,等待队列中除第一个线程以外的所有线程都会阻塞,CPU唤醒阻塞线程的开销比非公平锁大。

例子:

  • JDK中经过构造函数定义的ReentrantLock

    • new ReentrantLock(true)

1.2 非公平锁

多个线程加锁时,将直接尝试获取锁,获取不到才会到等待队列的队尾等待。但如果此时锁刚好可用,那么这个线程可以无需阻塞直接获取到锁。所以非公平锁有可能出现后申请锁的线程先获取锁的场景。

优点:可以减少唤起线程的开销,整体的吞吐效率高,因为线程有几率不阻塞直接获得锁,CPU不必唤醒所有线程。

缺点:处于等待队列中的线程可能会饿死,或者等很久才会获得锁。

例子:

  • JDK中的synchronized

  • JDK中默认的ReentrantLock

    • new ReentrantLock()
    • new ReentrantLock(false)

2. 独享锁和共享锁

2.1 独享锁/独占锁/排他锁(X锁)

指该锁一次只能被一个线程所持有。如果线程T对数据A加上排它锁后,则其他线程不能再对A加任何类型的锁。获得排它锁的线程即能读数据又能修改数据。

例子:

  • JDK中的synchronized和Lock的实现类

  • MySQL中的X锁

    • 加了X锁的记录,不允许其他事务再加S锁或者X锁

2.2 共享锁(S锁)

指该锁可被多个线程所持有。如果线程T对数据A加上共享锁后,则其他线程只能对A再加共享锁,不能加独享锁。获得共享锁的线程只能读数据,不能修改数据。

例子:

  • MySQL中的S锁

    • 加了S锁的记录,允许其他事务再加S锁,不允许其他事务再加X锁

3. 可重入锁和不可重入锁

3.1 可重入锁

广义上的可重入锁指的是可重复可递归调用的锁。在外层方法使用某一锁之后,在内层仍然可以使用,并且不发生死锁(前提得是同一个对象或者class),这样的锁就叫做可重入锁。

假设同一个类有A、B两个方法,且A、B都有被加上了同样的锁(比如都是this或是都是class),当A方法调用时,获得锁,在A方法的锁还没有被释放时,调用B方法时,B方法也获得该锁。即:当一个线程获得当前实例的锁lock,并且进入了被加上该锁的方法A,在方法A释放锁之前,可以再次进入隶属于同一个类的、被加上该锁的方法B。

注意:这种情景,既可以是不同的线程分别调用这个两个方法,也可是同一个线程,A方法中调用B方法,这个线程调用A方法。

例子:JDK中的synchronized和ReentrantLock

3.2 不可重入锁

与可重入锁相反,不可重入锁不可递归调用,递归调用就发生死锁。

一个类的A、B两个方法,A、B都有获得统一把锁,当A方法调用时,获得锁,在A方法的锁还没有被释放时,调用B方法时,B方法也获得不了该锁,必须等A方法释放掉这个锁。

当一个线程获得当前实例的锁lock,并且进入了方法A,在方法A释放锁之前,不可以再次进入方法B。

4. 乐观锁与悲观锁

4.1 乐观锁

乐观锁假定冲突的概率很低。

工作方式:先修改完共享资源,再验证这段时间内有没有发生冲突,如果没有其他线程在修改资源,那么操作完成,如果发现有其他线程已经修改过这个资源,就放弃本次操作。

场景:如果多线程同时修改共享资源的概率比较低,就可以采用乐观锁。

乐观锁全程并没有加锁,所以也叫无锁编程。

4.2 悲观锁

悲观锁做事比较悲观,它认为多线程同时修改共享资源的概率比较高

工作方式:访问共享资源前先要上锁

例子:自旋锁、互斥锁都是悲观锁。

0条评论
0 / 1000
林****珉
2文章数
0粉丝数
林****珉
2 文章 | 0 粉丝
林****珉
2文章数
0粉丝数
林****珉
2 文章 | 0 粉丝
原创

锁的分类

2024-07-26 09:57:31
15
0

1. 公平锁和非公平锁

1.1 公平锁

指多个线程按照申请锁的顺序来获取锁,线程直接进入队列中排队,队列中的第一个线程才能获得锁。

优点:等待锁的线程不会饿死。

缺点:整体吞吐效率相对非公平锁要低,等待队列中除第一个线程以外的所有线程都会阻塞,CPU唤醒阻塞线程的开销比非公平锁大。

例子:

  • JDK中经过构造函数定义的ReentrantLock

    • new ReentrantLock(true)

1.2 非公平锁

多个线程加锁时,将直接尝试获取锁,获取不到才会到等待队列的队尾等待。但如果此时锁刚好可用,那么这个线程可以无需阻塞直接获取到锁。所以非公平锁有可能出现后申请锁的线程先获取锁的场景。

优点:可以减少唤起线程的开销,整体的吞吐效率高,因为线程有几率不阻塞直接获得锁,CPU不必唤醒所有线程。

缺点:处于等待队列中的线程可能会饿死,或者等很久才会获得锁。

例子:

  • JDK中的synchronized

  • JDK中默认的ReentrantLock

    • new ReentrantLock()
    • new ReentrantLock(false)

2. 独享锁和共享锁

2.1 独享锁/独占锁/排他锁(X锁)

指该锁一次只能被一个线程所持有。如果线程T对数据A加上排它锁后,则其他线程不能再对A加任何类型的锁。获得排它锁的线程即能读数据又能修改数据。

例子:

  • JDK中的synchronized和Lock的实现类

  • MySQL中的X锁

    • 加了X锁的记录,不允许其他事务再加S锁或者X锁

2.2 共享锁(S锁)

指该锁可被多个线程所持有。如果线程T对数据A加上共享锁后,则其他线程只能对A再加共享锁,不能加独享锁。获得共享锁的线程只能读数据,不能修改数据。

例子:

  • MySQL中的S锁

    • 加了S锁的记录,允许其他事务再加S锁,不允许其他事务再加X锁

3. 可重入锁和不可重入锁

3.1 可重入锁

广义上的可重入锁指的是可重复可递归调用的锁。在外层方法使用某一锁之后,在内层仍然可以使用,并且不发生死锁(前提得是同一个对象或者class),这样的锁就叫做可重入锁。

假设同一个类有A、B两个方法,且A、B都有被加上了同样的锁(比如都是this或是都是class),当A方法调用时,获得锁,在A方法的锁还没有被释放时,调用B方法时,B方法也获得该锁。即:当一个线程获得当前实例的锁lock,并且进入了被加上该锁的方法A,在方法A释放锁之前,可以再次进入隶属于同一个类的、被加上该锁的方法B。

注意:这种情景,既可以是不同的线程分别调用这个两个方法,也可是同一个线程,A方法中调用B方法,这个线程调用A方法。

例子:JDK中的synchronized和ReentrantLock

3.2 不可重入锁

与可重入锁相反,不可重入锁不可递归调用,递归调用就发生死锁。

一个类的A、B两个方法,A、B都有获得统一把锁,当A方法调用时,获得锁,在A方法的锁还没有被释放时,调用B方法时,B方法也获得不了该锁,必须等A方法释放掉这个锁。

当一个线程获得当前实例的锁lock,并且进入了方法A,在方法A释放锁之前,不可以再次进入方法B。

4. 乐观锁与悲观锁

4.1 乐观锁

乐观锁假定冲突的概率很低。

工作方式:先修改完共享资源,再验证这段时间内有没有发生冲突,如果没有其他线程在修改资源,那么操作完成,如果发现有其他线程已经修改过这个资源,就放弃本次操作。

场景:如果多线程同时修改共享资源的概率比较低,就可以采用乐观锁。

乐观锁全程并没有加锁,所以也叫无锁编程。

4.2 悲观锁

悲观锁做事比较悲观,它认为多线程同时修改共享资源的概率比较高

工作方式:访问共享资源前先要上锁

例子:自旋锁、互斥锁都是悲观锁。

文章来自个人专栏
文章 | 订阅
0条评论
0 / 1000
请输入你的评论
1
0