锁
-
独享锁
也叫排他锁该锁每次只能被一个线程持有. ReentrantReadWriteLock的写锁 ,synchronized
-
共享锁
该锁可以被多个线程持有.ReentrantLock,ReentrantReadWriteLock 里的读锁时共享锁
独享锁与共享锁都是通过AQS来实现的
-
互斥锁
再访问共享资源之前进行加锁操作,访问完之后进行解锁操作.加锁后,其他线程想要获取资源会被阻塞,指定当前线程解锁
-
读写锁
读锁是共享锁,写锁是互斥(排他)锁.
-
乐观锁
假设最好的情况下,每次拿数据的时候都认为别的线程不会修改,所以不会上锁.在更新的时候会判断期间有没有别的线程更新这个数据.一般使用版本号或者CAS算法实现.多用于读类型的应用.列入AtomicInteger
-
悲观锁
假设最坏的情况下,每次拿数据的时候都认为会被别的线程修改,所以每次拿数据的时候会上锁,这样别的线程拿数据的时候会被阻塞.ReentrantLock,与synchronized都属于悲观锁
-
可重入锁
当一个线程在同一个对象内可以重复递归调用的锁,外层使用锁后,不需要释放内层仍然可以使用,且不发生死锁情况.可重入锁的意义就是防止放生死锁 synchronized与ReentrantLock都是可重入锁
public abstract class Test2 { // 当method1调用method2时候,线程可以再次获取锁 public synchronized void method1(){ method2(); } public synchronized void method2(){ } }
-
不可重入锁
与可重入锁相反.同一个线程中当eat()方法调用sleep()方法时不释放锁,线程会一直处于自旋状态.此时放生死锁,等待自己释放锁,在区获取锁调用sleep()方法.
public class Test2 { UnReentrantLock unReentrantLock = new UnReentrantLock(); public static void main(String[] args) { Test2 test2 = new Test2(); new Thread(()->{ test2.eat(); }).start(); } public void eat(){ unReentrantLock.lock(); System.out.println("吃饭"); //如果不释放该锁,线程会一直循环自旋,放生死锁 //unReentrantLock.unlock(); sleep(); } public void sleep(){ unReentrantLock.lock(); System.out.println("睡觉"); //unReentrantLock.unlock(); } } /* *不可重入自旋锁 */ class UnReentrantLock{ private AtomicReference<Thread> reference = new AtomicReference<>(); public void lock() { Thread current = Thread.currentThread(); // 自旋 for (; ; ) { if (reference.compareAndSet(null, current)) { return; } } } public void unlock() { Thread current = Thread.currentThread(); reference.compareAndSet(current, null); } }
-
自旋锁
当一个线程尝试获取锁的时候,如果该锁被其他线程占用,这个线程会循环等待锁释放,指定获取到锁才退出
1 自旋锁会让线程一直处于活跃状态,线程不会进入阻塞状态,避免了CPU上下文切换.如果线程过多会造成CPU高耗.