锁的种类和特点
# 锁的种类和特点
锁的种类有七种
- 偏向锁/轻量级锁/重量级锁
- 可重入锁/不可重入锁
- 共享锁/独占锁
- 公平锁/非公平锁
- 乐观锁/悲观锁
- 自旋锁/非自旋锁
- 可中断锁/不可中断锁
# 偏向锁/轻量级锁/重量级锁
这三种是JVM为了提升synchronized修饰的方法的并发性能,而出现的锁。
实现方式是通过对象头中的mark word 字段,来表明锁的状态。
偏向锁
偏向锁指的是,如果一段代码的并发程度很低,只有一个线程在请求锁,那么其实就没有必要上锁,JVM的做法是,当一个对象被初始化之后,这个时候就是可偏向的,在第一个线程访问锁的时候会在这个对象标记上线程的信息,那么在下一次还是这个线程请求,就直接获取到锁,开销比较小,性能好
轻量级锁
轻量级锁,synchronized修饰的方法被多个线程访问,就会从偏向锁升级成轻量级锁。因为在绝大多数的情况下,线程都是交替执行只存在于少量的竞争,这个时候轻量级锁会通过CAS方式进行自旋,不会陷入到阻塞
重量级锁
重量级锁,是在操作系统层实现的一个完全互斥的锁。当有多个线程在竞争,且竞争的时间过长的时候,轻量级锁就会膨胀成重量级锁。重量级锁会让其他没有获取到锁的线程进入阻塞状态。
所以,synchronized的锁是会经历 无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁 这几个过程,这个过程也被称之为锁的膨胀。
其中,偏向锁性能最好,轻量级锁由于CAS自旋,所以性能次之,重量级锁存在线程的阻塞和唤醒,性能最差。
# 可重入锁/不可重入锁
可重入锁是指,在线程当前已经持有这把锁了,在不释放这把锁的情况下,再次获取这把锁。
不可重入锁是指,在线程当前已经只有这把锁了,必须得先释放掉持有的锁,才能够重新获取锁。
对于可重入锁而言,最典型的就是 ReentrantLock 了,正如它的名字一样,reentrant 的意思就是可重入,它也是 Lock 接口最主要的一个实现类。
# 共享锁/独占锁
最好能够全是共享锁和独占锁的是读写锁
。读文件的时候,可以多个线程读取一个文件,但是在写入的时候只允许一个线程进行写入。
当读写锁是写加锁状态时, 在这个锁被解锁之前, 所有试图对这个锁加锁的线程都会被阻塞.
当读写锁在读加锁状态时, 所有试图以读模式对它进行加锁的线程都可以得到访问权, 但是如果线程希望以写模式对此锁进行加锁, 它必须直到所有的线程释放锁.
通常, 当读写锁处于读模式锁住状态时, 如果有另外线程试图以写模式加锁, 读写锁通常会阻塞随后的读模式锁请求, 这样可以避免读模式锁长期占用, 而等待的写模式锁请求长期阻塞.
# 公平锁/非公平锁
公平锁是指,在线程拿不到锁的时候会进入到等待,开始排队,在队列中等待时间长的会优先分配到锁,先来先得。
非公平锁是指,在线程拿不到锁的时候,开始排队,但是分配上是会忽略掉排队时间,随机分配到一个线程上
# 乐观锁/悲观锁
悲观锁在获取到资源之前,必须先拿到锁,JVM的重量级锁就是一种悲观锁,只有在独占锁的时候,才回去操作资源。
乐观锁在获取资源之前无需拿到锁,只有在最后更新的时候,会通过CAS的方式去更新资源,JVM的轻量级锁与之类似
# 自旋锁/非自旋锁
自旋锁的理念是如果线程现在拿不到锁,并不直接陷入阻塞或者释放 CPU 资源,而是开始利用循环,不停地尝试获取锁,这个循环过程被形象地比喻为“自旋”,就像是线程在“自我旋转”。相反,非自旋锁的理念就是没有自旋的过程,如果拿不到锁就直接放弃,或者进行其他的处理逻辑,例如去排队、陷入阻塞等。
# 不可中断锁/可中断锁
在 Java 中,synchronized 关键字修饰的锁代表的是不可中断锁,一旦线程申请了锁,就没有回头路了,只能等到拿到锁以后才能进行其他的逻辑处理。而我们的 ReentrantLock 是一种典型的可中断锁,例如使用 lockInterruptibly 方法在获取锁的过程中,突然不想获取了,那么也可以在中断之后去做其他的事情,不需要一直傻等到获取到锁才离开。
- 01
- 以 root 身份启动 transmission-daemon12-13
- 02
- Debian系统安装qbittorrent-nox12-09
- 03
- LXC Debain12安装zerotier并实现局域网自动nat转发07-29