1.公平锁/非公平锁
公平锁指多个线程按照申请的顺序获得锁。
非公平锁指线程获取锁的顺序可能跟申请的顺序不一致。有可能出现优先级反转或饥饿现象。
对于java而言ReentrantLock根据构造函数可以指定成公平锁和非公平锁,默认是非公平锁。synchronized是一种非公平锁,由于它并不像reentrantLock是通过AQS实现的。
2.可重入锁
可重入锁又称递归锁,即线程在外层方法获取的锁再进入内层方法会自动获取锁。对于Java而言,ReentrantLock和synchronized都是可重入锁,可重入锁再一定程度上可以避免死锁。
3.独享锁/共享锁
独享锁是指一次只被一个线程持有。
共享锁是指一次可被多个线程持有。
Java 中reentrantLock是独享锁,但对于Lock的另一个实现ReadWriteLock,其读锁是共享锁,写锁是独享锁。读锁可以保证并发读是高效的。读写,写读,写写是互斥的。对于synchronized是独享锁。
4.互斥锁/读写锁
互斥锁/读写锁就是上面提到的独享锁/共享锁的具体实现。
Java 中互斥锁就是reentrantLock。
读写锁的实现就是ReadWriteLock。
5.乐观锁/悲观锁
乐观锁和悲观锁更适合说是一种看待同步的态度。
乐观锁认为对于同一个数据的并发操作是不会发生修改的,在更新数据的时候会尝试更新,不断的重试去更新数据。
悲观锁认为对于同一个数据的并发操作,一定会发生修改的,哪怕没有修改也会认为是修改,因此悲观🔒对于一切并发的操作都采用加锁的方式,认为不加锁的并发都会出问题。
从上面总结,悲观锁比较适合写操作比较多的场景,而乐观锁比较适合付操作的场景(es).
Java中的各种锁可以理解是悲观锁,乐观锁在Java中经常采用的是CAS算法,例如原子类,采用CAS自旋来实现原子更新。
6.分段锁
分段锁可以说是一种锁的设计,例如ConcurrentHashMap就是使用分段锁来进行高效的并发操作。
7.偏向锁/轻量级锁/重量级锁
这三种锁是指锁的状态(偏向锁—>轻量级锁—>重量级锁),并且是针对Synchronized。在Java 5通过引入锁升级的机制来实现高效Synchronized。这三种锁的状态是通过对象监视器在对象头中的字段来表明的。
偏向锁是指一段同步代码一直被一个线程所访问,那么该线程会自动获取锁。降低获取锁的代价。
轻量级锁是指当锁是偏向锁的时候,被另一个线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,提高性能。
重量级锁是指当锁为轻量级锁的时候,另一个线程虽然是自旋,但自旋不会一直持续下去,当自旋一定次数的时候,还没有获取到锁,就会进入阻塞,该锁膨胀为重量级锁。重量级锁会让其他申请的线程进入阻塞,性能降低。
8.自旋锁
自旋锁是指尝试获取锁的线程不会立即进入阻塞状态,而是循环获取锁,这样做的好处是减少线程上下文切换的消耗,缺点循环会导致CPU飙高。