多线程 锁策略 ( 悲观/乐观锁 读写/互斥锁 重量/轻量级锁挂起等待/自旋锁 公平/非公平锁 可重入/不可重入锁)

Posted Perceus

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程 锁策略 ( 悲观/乐观锁 读写/互斥锁 重量/轻量级锁挂起等待/自旋锁 公平/非公平锁 可重入/不可重入锁)相关的知识,希望对你有一定的参考价值。

@TOC


一、常见的锁策略

1. 悲观锁 VS 乐观锁

悲观锁 :

就是它认为,只要它一加锁,就会出现锁冲突

乐观锁:

就是说:它加锁没有那么容易就会出现锁冲突。


思考一个问题:

悲观锁的事情做得多

举例:

分析:


2. 读写锁 vs 普通的互斥锁

==只要两个线程对同一个对象加锁,就会产生互斥==


对于读写锁,就相当于将 读锁 和 写锁 给分开了

分开了有什么好处呢 ?


读写锁在Java 标准库提供了 ReentrantReadWriteLock 类, 实现了读写锁.


  1. ReentrantReadWriteLock.ReadLock 类表示一个 读锁. 这个对象提供了 lock / unlock 方法进行加锁解锁.

  2. ReentrantReadWriteLock.WriteLock 类表示一个 写锁. 这个对象也提供了 lock / unlock 方法进行加锁解锁.

3. 重量级锁 vs 轻量级锁

这个两个锁 和 上面的悲观乐观两个锁,含义上有一定的重叠。


重量级锁就是做了更多的事情,开销很大。

轻量级锁,做的事情很少,开销也就很小。


更具体的来说:


4. 挂起等待锁 vs 自旋锁

  • 挂起等待锁:往往就是通过内核的一些机制来实现的,往往较重 [重量级锁的一种典型实现]
  • 自旋锁:往往是通过用户态代码来实现的,往往较轻 [轻量级锁的一种典型实现]

==理解自旋锁 vs 挂起等待锁==


小结


5. 公平锁 VS 非公平锁

这俩可能有点容易搞反,要记住

对于操作系统来说,本身线程之间的调度就是随机的(机会均等),操作系统提供的mutex这个锁,就属于非公平锁

线程之间不是存在优先级嘛?优先级难道不会影响调度吗?


6. 可重入锁 和 不可重入锁

重入锁实现


理解 “把自己锁死”
一个线程没有释放锁, 然后又尝试再次加锁

// 第一次加锁, 加锁成功
lock();
// 第二次加锁, 锁已经被占用, 阻塞等待.
lock();

例子:
一个人闪现进了上锁的厕所,里面出不去,外面进不来


synchronized 与 锁策略的对应关系

谈谈常用的synchronized这把锁:


二、相关面试题

1. 你是怎么理解乐观锁和悲观锁的,具体怎么实现呢?


2. 介绍下读写锁?


3. 什么是自旋锁,为什么要使用自旋锁策略呢,缺点是什么?

相比于挂起等待锁优点:

缺点:


4. synchronized 是可重入锁么?

是可重入锁.

举例:

public class Xttblog extends SuperXttblog 
    public static void main(String[] args) 
        Xttblog child = new Xttblog();
        child.doSomething();
    

    public synchronized void doSomething() 
        System.out.println("child.doSomething()" + Thread.currentThread().getName());
        doAnotherThing(); // 调用自己类中其他的synchronized方法
    

    private synchronized void doAnotherThing() 
        super.doSomething(); // 调用父类的synchronized方法
        System.out.println("child.doAnotherThing()" + Thread.currentThread().getName());
    


class SuperXttblog 
    public synchronized void doSomething() 
        System.out.println("father.doSomething()" + Thread.currentThread().getName());
    

结果:

child.doSomething()Thread-5492
father.doSomething()Thread-5492
child.doAnotherThing()Thread-5492

还看不懂?那我就再解释下!


以上是关于多线程 锁策略 ( 悲观/乐观锁 读写/互斥锁 重量/轻量级锁挂起等待/自旋锁 公平/非公平锁 可重入/不可重入锁)的主要内容,如果未能解决你的问题,请参考以下文章

多线程常见的锁策略

多线程常见的锁策略

多线程常见的锁策略

悲观锁和乐观锁

悲观锁和乐观锁

Linux 线程安全常用的锁机制