目录
-
锁的概念
- 锁,顾名思义,能用锁单独占有一些东西,让其他人不能正常使用,而在程序中意义就是在多线程情况下,需要用锁去锁住一些共享的资源,只有拿到锁的线程才能访问这些资源,而其它未拿到锁的线程只能等待拿到锁的线程释放锁之后,再去和其他线程竞争锁以获取对资源的访问,目的就是解决在并发操作下共享资源被多个线程访问导致的异常情况(例如数据前后不一致)。
-
锁的常见分类
-
乐观锁和悲观锁
- 乐观锁:乐观锁认为自己在使用数据的时候不会有别的线程修改数据,所以不会添加锁,只是在更新数据的时候去判断之前有没有别的线程修改了数据,如果这个数据没有被更新,当前线程将自己修改的数据成功写入,如果数据已经被其他线程更新,则根据不同的实现方式执行不同的操作
- 悲观锁:悲观锁认为自己在使用数据的时候一定有别的线程来修改数据,因此在获取数据的时候会先加锁,确保数据不会被别的线程修改,java中synchronized和lock的实现类都是悲观锁
- 适用场景:乐观锁适合读数据较多的场景,悲观锁适合写数据较多的场景
-
公平锁和非公平锁
- 公平锁:多个线程按照申请锁的先后顺序来获取锁,线程直接进入队列中排队排在前面的线程会优先获得锁
- 非公平锁:多个线程加锁时直接尝试去获取锁,获取不到才会进入等待队列的队尾等待,但如果此时锁刚好可用,那么这个线程可以无需等待直接获取锁
- 优缺点
- 公平锁:
- 优点:等待锁的线程不会饿死的情况
- 缺点:唤醒阻塞线程的开销较大
- 非公平锁:
- 优点:可以减少唤醒线程的开销,整体的吞吐率较高
- 缺点:处于等待队列的线程可能会被饿死
- 公平锁:
-
可重入锁和不可重入锁
- 可重入锁:当一个线程获取一个对象上的锁的时候,会自动获取该对象的其他锁,而其他线程不可获取该对象的任何锁(当一个线程获取对象方法外层的锁时,会自动获取内层的锁)
- 不可重入锁:当一个线程获取一个对象上外层方法的锁的时候,如果接下来的方法又需要获取另一个锁,则需要先等待锁释放才能获取下一个
-
独占锁(排它锁)和共享锁
- 独占锁(排它锁):当一个线程获取到锁的时候,其他线程不能再获取该锁,只能进入队列等待锁的释放,此时,获取锁的线程可以读取和写入数据
- 共享锁:当一个线程获取到共享锁的时候,其他线程也能获取共享锁,但是只能读取数据,不能写入数据
-
读写锁(ReadWriteLock)
- 读锁:多个线程可以共享一起执行
- 写锁:独占锁
-
死锁
- 概念:多个进程在运行过程之中因争夺资源而造成的一种僵局
- 产生四个条件(必须同时满足)
- 请求与保持条件:一个进程因请求而获得资源而阻塞时,对已获得的资源保持不放
- 不剥夺资源:进程已获得的资源,在未使用完成前,不能强行剥夺
- 互斥条件:一个资源只能被一个进程使用
- 循环等待条件:若干进程之前形成一种头尾相接的循环等待资源关系
- 解除死锁
- 剥夺资源:从其他进程中剥夺足够的资源给死锁进程,从而解除死锁
- 撤销进程:可以直接撤销死锁进程或撤销代价最小的进程,直至资源足够可用,死锁状态消除为止
-