1. Lock
互斥的,在请求锁时如果该锁别其它线程获取的时候,该线程将会被阻塞,放在该锁的阻塞队列中,当线程释放锁时,被阻塞的线程会被激活来判断是否是阻塞队列的头结点将会获得锁,依次下去。
其中的阻塞队列是FIFO队列,这也是最简单的线程调用策略了。
2. 可重入锁(ReentrantLock)
相对于Lock,可重入锁式支持同一个线程获取锁的。列入递归方法,在方法中还可以调用该方法的。
但是Lock不支持重入,会出现线程被自己阻塞的情况。(当前线程正在运行,当该线程请求锁时,返回的false,这样改线程会被阻塞,这样正在运行的该线程也会被阻塞)
重点知识
- 如何实现可重入
- 如何实现公平性(原则是:现请求锁的线程,先获得锁)
公平性
公平
其实就是按照FIFO的原则,每次在等待队列的头部获取线程来得到锁
- 性能比较低,因为每次都要切换
非公平
-
默认是非公平的
-
相比于公平,非公平性能更高,但是可能会产生死锁。
3. 读写锁
将排他锁分成读写锁,也就是将读操做和写操作分开控制。
同一时刻可以允许多个读锁,但是当又写锁时,其它所有的读写操做都要被阻塞,当该读锁释放时,被阻塞的读写操做才恢复。这样保证数据的一直性,保证不会出现脏读的情况。
特点
-
公平性
-
可重入性
-
锁降级(写锁可以降级为读锁)
4. ReentrantReadWriteLock
读写状态的设计
通过将32位整形变量分成高16位和低16位,高16位为写状态,低16位为读状态。
通过位操作来实现对读写状态的维护
写锁的获取与释放
写锁的获取与释放和Lock很类似,因为写锁其实也会是排他锁。同一时刻只有唯一的一个写操作获取写锁。
读锁的获取与释放
锁降级
先获取读锁,准备好写入的数据,在获取读锁,这样就实现了从写锁到读锁的降级。
- 为什么不直接释放写锁呢?还要获取读锁,这样讲避免,释放写锁之后,其他线程获取写锁将数据更改,但是当前线程是感知不到这种变化的。如果获取读锁,要获取读锁的线程将会被阻塞,这样就避免了这种情况。