常见锁的分类

1. 悲观锁

悲观锁指对数据被外界修改持保守态度,认为数据很容易就会被其他线程修改,所以在数据被处理前先对数据进行加锁,
并在整个数据处理过程中,使数据处于锁定状态。
悲观锁主要分为共享锁和排他锁

  1. 共享锁【Shared lock】又称为读锁,简称S锁。顾名思义,共享锁就是多个事务对于同一数据可以共享一把锁,
    都能访问到数据,但是只能读不能修改。
  2. 排他锁【Exclusive lock】又称为写锁,简称X锁。顾名思义,排他锁就是不能与其他锁并存,
    如果一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁,包括共享锁和排他锁,

但是获取排他锁的事务是可以对数据行读取和修改。
例如:java中的synchronized关键字、接口Lock的实现类、mysql的select…for update等

2. 乐观锁

乐观锁是相对悲观锁来说的,它认为数据在一般情况下不会造成冲突,所以在访问记录前不会加排它锁,
而是在进行数据提交更新时,才会正式对数据冲突与否进行检测。
例如:使用数据版本(Version++)记录机制实现、使用时间戳、java中Atomic的CAS等

3. 公平锁

公平锁表示线程获取锁的顺序是按照线程请求锁的时间早晚来决定的,也就是最早请求锁的线程将最早获取到锁
例如:ReentrantLock pairLock = new ReentrantLock(true);

4. 非公平锁

非公平锁表示线程获取锁的顺序不一定是先到先得。
例如:ReentrantLock unpairLock = new ReentrantLock(false)。如果构造函数不传递参数,则默认是非公平锁。

5. 独占锁

独占锁是任何时候都只有一个线程能得到锁。
例如:Java的ReentrantLock

6. 共享锁

共享锁是可以同时由多个线程持有,它允许一个资源可以被多线程同时进行读操作。
例如:ReentrantReadWriteLock的读锁

7. 可重入锁

可重入锁又名递归锁,是指在同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁。原理是在锁内部维护一个线程标示,用来标示该锁目前被哪个线程占用,然后关联一个计数器。一开始计数器值为0,说明该锁没有被任何线程占用。当一个线程获取了该锁时,计数器的值会变成1,这时其他线程再来获取该锁时会发现锁的所有者不是自己而被阻塞挂起。
例如:

public sychrnozied void test() {
    xxxxxx;
    test2();
}
public sychronized void test2() {
    yyyyy;
}

8. 自旋锁

自旋锁是线程获取锁的时候,如果锁被其他线程持有,则当前线程将循环等待,直到获取到锁。