并发编程(六):AQS之读写锁ReentrantReadWriteLock

偏执的太偏执、 2023-06-04 10:58 105阅读 0赞

一,AQS源码博文:并发编程:AbstractQueuedSynchronizer源码分析

二,ReentrantReadWriteLock读写锁介绍

1,读写锁介绍

  1. *ReentrantReadWriteLock* 虽然与 *ReentrantLock* 没有直接关系,但是在功能上算是对 *ReentrantLock* 的扩展。在 *ReentrantLock* 重入独占锁的功能上,添加了共享锁的扩展,分别对应 *ReentrantReadWriteLock* 的写锁(*WriteLock*)和读锁(*ReadLock*)。*ReentrantReadWriteLock* 内部定义 *Sync* 类继承自 *AQS* 对加锁方式进行扩展,在读锁写锁获取以及读写锁交叉获取提供了自身机制,以此保证线程同步。*ReentrantReadWriteLock* 在加锁过程中,对 *Integer* 32位进行分割,以高16位表示共享锁,以低16位表示独占锁。在进行加锁时,通过左移右移以及与运算判断当前加锁状态及重入状态,并进线程进行调度。

2,类图

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTE5NzYzODg_size_16_color_FFFFFF_t_70

  1. \* *ReentrantReadWriteLock* 实现自 *ReadWriteLock* 接口,并在内部定义了锁实现了相关内部类。
  2. \* *Sync*,*FairSync*,*NonfairSync* 三个内部类是对 AQS 的层次扩展,用来扩展加锁的一系列逻辑处理
  3. \* *WriteLock*,*ReadLock* 两个内部类实现自 *Lock* 接口,并通过 *ReentrantReadWriteLock* 创建后对外提供,在应用层进行不同的加锁处理

3,常用API

  1. // 创建读写锁, 通过参数指定公平锁/非公平锁
  2. public ReentrantReadWriteLock();
  3. public ReentrantReadWriteLock(boolean fair);
  4. // 创建读锁
  5. public ReentrantReadWriteLock.ReadLock readLock()
  6. // 创建写锁
  7. public ReentrantReadWriteLock.WriteLock writeLock();
  8. // 尝试加锁
  9. public boolean tryLock();
  10. public boolean tryLock(long timeout, TimeUnit unit);
  11. // 加锁
  12. public void lock();
  13. public void lockInterruptibly() throws InterruptedException;
  14. // 释放锁
  15. public void unlock();
  16. \* 在上述API中,关于锁操作的一些API,都存在读锁和写锁的区别;其中,在读锁和写锁的处理中,又存在公平锁和非公平锁的区分;
  17. \* 后续源码分析中,读锁和写锁会分别分析,但是公平锁和分公平锁只对非公平锁进行分析,公平锁参考[重入锁][Link 1]

4,ReentrantReadWriteLock 加锁分析

4.1,整体锁状态存储

  1. \* *ReentrantReadWriteLock* 在锁状态存储中,对 Integer 32位进行拆分,使用高16位存储共享锁,使用低16位存储独占锁。所以无论是共享锁的共享次数还是独占锁的重入次数,最高为(*(1 << 16) - 1*)。
  2. // 1 << 16就是1在二进制情况下右移16位结果为
  3. 10000 0000 0000 0000 = 2^16 = 65536
  4. // (1 << 16) - 1也是在二进制下进行减操作
  5. 1111 1111 1111 1111 = 2^16 - 1 = 65535
  6. \* *ReentrantReadWriteLock *在独占锁加锁时,是对低16位进行加1,在获取独占锁的重入次数时,也是对低16位进行与运算以获取结果加锁具体看代码框
  7. // 独占锁state递增
  8. compareAndSetState(c, c + 1)
  9. // 独占锁获取重入次数
  10. // EXCLUSIVE_MASK:常量,最终结果为 (1111 1111 1111 1111),也就是对应 Integer 的低16位
  11. // 用c和 EXCLUSIVE_MASK 进行与运算,也就是用c的低16位和 EXCLUSIVE_MASK 进行与运算,
  12. // 与运算同1为1,其余为0,所以获取到的结果就是c的低16位表示的数字,然后再默认转换10进制,即为重入数量
  13. static int exclusiveCount(int c) {
  14. return c & EXCLUSIVE_MASK;
  15. }
  16. static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
  17. static final int SHARED_SHIFT = 16;
  18. // 比如,此时共享为3次,重入为0次,则c的二进制表示为
  19. 0000 0000 0000 0011 0000 0000 0000 0000
  20. // EXCLUSIVE_MASK的二进制表示为
  21. 0000 0000 0000 0000 1111 1111 1111 1111
  22. // 运算结果
  23. 0000 0000 0000 0011 0000 0000 0000 0000
  24. & 0000 0000 0000 0000 1111 1111 1111 1111
  25. -------------------------------------------
  26. 0000 0000 0000 0000 0000 0000 0000 0000 = 0
  27. // 所以此时获取到的独占锁数量为0
  28. // 假设可以获取成功,则对独占锁递增,通过CAS,用c + 1代替 c,此时,c的二进制表示为:
  29. 0000 0000 0000 0011 0000 0000 0000 0001
  30. // 这时候继续计算,获取独占锁的次数,运算如下
  31. 0000 0000 0000 0011 0000 0000 0000 0001
  32. & 0000 0000 0000 0000 1111 1111 1111 1111
  33. -------------------------------------------
  34. 0000 0000 0000 0000 0000 0000 0000 0001 = 1
  35. \* 同样,*ReentrantReadWriteLock *在对共享锁加锁时,是对高16位进行加锁,在获取共享锁次数时,先对 *state* 无符号右移16位,然后直接获取结果,具体过程如代码框
  36. // 加锁成功后,c递增,按照重入逻辑,递增应该为1
  37. // 而此时递增了(1 << SHARED_SHIFT),也就是二进制下 1 0000 0000 0000 0000
  38. // 除去低16位,也就是刚好在高16位上递增1
  39. compareAndSetState(c, c + SHARED_UNIT)
  40. static final int SHARED_UNIT = (1 << SHARED_SHIFT);
  41. static final int SHARED_SHIFT = 16;
  42. // 共享锁获取锁重入次数
  43. // 直接将state无符号右移16位,表示的就是共享锁的重入次数
  44. // 而右移去掉的16位,也就刚好是独占锁表示的低16位
  45. static int sharedCount(int c) {
  46. return c >>> SHARED_SHIFT;
  47. }
  48. static final int SHARED_SHIFT = 16;
  49. // 继续举例,比如此时共享次数3,独占次数为3,则state的二进制表示为
  50. 0000 0000 0000 0011 0000 0000 0000 0011
  51. // 无符号右移16位后,高位补0,值如下
  52. 0000 0000 0000 0000 0000 0000 0000 0011 = 3
  53. // 假设此时共享锁获取成功,state加上(1 << SHARED_SHIFT),如下
  54. 0000 0000 0000 0011 0000 0000 0000 0011
  55. + 0000 0000 0000 0001 0000 0000 0000 0000
  56. -------------------------------------------
  57. 0000 0000 0000 0100 0000 0000 0000 0000
  58. // 此时继续获取数量,对state无符号右移16位,结果如下
  59. 0000 0000 0000 0000 0000 0000 0000 0100 = 4

5,功能DEMO

  1. package com.gupao.concurrent;
  2. import java.util.concurrent.locks.ReentrantReadWriteLock;
  3. /**
  4. * @author pj_zhang
  5. * @create 2019-10-19 12:37
  6. **/
  7. public class ReadAndWriteLockTest {
  8. private static ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
  9. private static ReentrantReadWriteLock.ReadLock readLock = reentrantReadWriteLock.readLock();
  10. private static ReentrantReadWriteLock.WriteLock writeLock = reentrantReadWriteLock.writeLock();
  11. public static void main(String[] args) throws InterruptedException {
  12. testReadAndWriteLock();
  13. }
  14. public static void testWriteAndReadLock() throws InterruptedException {
  15. new Thread(() -> {
  16. System.out.println("开始获取锁。。。");
  17. // 先获取写锁后获取读锁
  18. // 读锁会顺利获取
  19. writeLock.lock();
  20. System.out.println("获取写锁成功。。。");
  21. readLock.lock();
  22. System.out.println("获取读锁成功。。。");
  23. writeLock.unlock();
  24. System.out.println("释放读锁成功。。。");
  25. readLock.unlock();
  26. System.out.println("释放写锁成功");
  27. }, "READ_AND_WRITE").start();
  28. }
  29. public static void testReadAndWriteLock() throws InterruptedException {
  30. new Thread(() -> {
  31. System.out.println("开始获取锁。。。");
  32. // 先获取读写再获取写锁
  33. // 此时已经存在锁,则独占锁获取失败
  34. readLock.lock();
  35. System.out.println("获取读锁成功。。。");
  36. writeLock.lock();
  37. System.out.println("获取写锁成功。。。");
  38. writeLock.unlock();
  39. System.out.println("释放读锁成功。。。");
  40. readLock.unlock();
  41. System.out.println("释放写锁成功");
  42. }, "READ_AND_WRITE").start();
  43. }
  44. /**
  45. * 不同线程测试读写锁
  46. *
  47. * @throws InterruptedException
  48. */
  49. public static void testLockWithDiffThread() throws InterruptedException {
  50. // 先启动一个读锁
  51. new Thread(() -> {
  52. System.out.println(Thread.currentThread().getName() + "加读锁前执行。。。, time: " + System.currentTimeMillis());
  53. readLock.lock();
  54. System.out.println(Thread.currentThread().getName() + "加读锁后执行。。。, time: " + System.currentTimeMillis());
  55. sleep(1000);
  56. readLock.unlock();
  57. }, "READ_1").start();
  58. Thread.sleep(10);
  59. // 再一个一个读锁,模拟读锁不阻塞
  60. new Thread(() -> {
  61. System.out.println(Thread.currentThread().getName() + "加读锁前执行。。。, time: " + System.currentTimeMillis());
  62. readLock.lock();
  63. System.out.println(Thread.currentThread().getName() + "加读锁后执行。。。, time: " + System.currentTimeMillis());
  64. sleep(1000);
  65. readLock.unlock();
  66. }, "READ_2").start();
  67. Thread.sleep(10);
  68. // 启动一个写锁,模拟写锁阻塞
  69. new Thread(() -> {
  70. System.out.println(Thread.currentThread().getName() + "_加写锁前执行。。。, time: " + System.currentTimeMillis());
  71. writeLock.lock();
  72. System.out.println(Thread.currentThread().getName() + "_加写锁后执行。。。, time: " + System.currentTimeMillis());
  73. sleep(1000);
  74. writeLock.unlock();
  75. }, "WRITE").start();
  76. Thread.sleep(10);
  77. // 自启动一个读锁,模拟共享锁执行时,阻塞一个写锁,之后再获取读锁,在写锁后执行
  78. new Thread(() -> {
  79. System.out.println(Thread.currentThread().getName() + "加读锁前执行。。。, time: " + System.currentTimeMillis());
  80. readLock.lock();
  81. System.out.println(Thread.currentThread().getName() + "加读锁后执行。。。, time: " + System.currentTimeMillis());
  82. sleep(1000);
  83. readLock.unlock();
  84. }, "READ_3").start();
  85. }
  86. private static void sleep(long millSeconds) {
  87. try {
  88. Thread.sleep(millSeconds);
  89. } catch (InterruptedException e) {
  90. e.printStackTrace();
  91. }
  92. }
  93. }
  94. \* testLockWithDiffThread() 执行结果:
  95. 1)在不同线程间,读锁间共享,不会进行锁竞争,通过CPU调度依次执行
  96. 2)写锁排斥,在尝试获取写锁时,会先判断是否存在线程持有写锁或者读写,如果存在,则添加到AQS同步队列中等待唤醒
  97. 3)写锁等待后,再启动一个读锁,此时因为写锁等待,并且已经对低16位的独占锁标识进行修改,且锁线程与当前线程不一致。则当前读锁线程获取锁失败,依次进入AQS队列等待

20191019135821604.png

  1. \* testReadAndWriteLock 执行结果
  2. 1)在同一线程后,尝试获取两种锁,从打印结果可以看出,线程获取读锁后,再获取写锁时阻塞,等待读锁释放
  3. 2)线程在获取读锁后,对高16进行修改,并设置锁线程为当前线程
  4. 3)线程继续获取写锁,因为高位已经被修改,所以写锁获取失败,等待读锁释放

20191019140900774.png

  1. \* testWriteAndReadLock 执行结果
  2. 1)在同一线程中,尝试获取两种所,从打印结果可以看出,线程获取写锁后,再获取读锁成功
  3. 2)线程获取写锁后,对低16位进行修改,并设置锁线程为当前线程
  4. 3)线程继续获取读锁,虽然判断独占线程已经存在,但是加锁线程表示当前线程,所以线程获取锁成功

20191019141635313.png

三,ReentrantReadWriteLock部分源码分析

1,初始化部分

  1. \* ReentrantReadWriteLock():调用重载构造器,并传递参数表示默认非公平锁
  2. public ReentrantReadWriteLock() {
  3. this(false);
  4. }
  5. \* ReentrantReadWriteLock(boolean fair)
  6. public ReentrantReadWriteLock(boolean fair) {
  7. // 通过入参表示公平锁还是非公平锁
  8. sync = fair ? new FairSync() : new NonfairSync();
  9. // 初始化读写锁对象
  10. readerLock = new ReadLock(this);
  11. writerLock = new WriteLock(this);
  12. }
  13. \* 初始化读写锁
  14. // 初始化读锁
  15. protected ReadLock(ReentrantReadWriteLock lock) {
  16. sync = lock.sync;
  17. }
  18. // 初始化写锁
  19. protected WriteLock(ReentrantReadWriteLock lock) {
  20. sync = lock.sync;
  21. }
  22. \* 获取读写锁
  23. // 获取写锁
  24. public ReentrantReadWriteLock.WriteLock writeLock() {
  25. return writerLock;
  26. }
  27. // 获取读锁
  28. public ReentrantReadWriteLock.ReadLock readLock() {
  29. return readerLock;
  30. }

四,ReentrantReadWriteLock.ReadLock源码分析

1,尝试加锁

  1. \* tryLock():直接通过 *Sync* 尝试加读锁
  2. public boolean tryLock() {
  3. return sync.tryReadLock();
  4. }
  5. \* tryReadLock()
  6. final boolean tryReadLock() {
  7. // 获取当前线程
  8. Thread current = Thread.currentThread();
  9. // 自旋尝试获取锁,可能存在线程竞争导致的CAS失败问题
  10. for (;;) {
  11. // 获取当前的加锁次数,注意此处次数是经过高低位处理后的次数,并不是真实次数,需要进行解析
  12. int c = getState();
  13. // exclusiveCount:低16位解析,获取独占锁数量,判断是否存在独占锁
  14. // getExclusiveOwnerThread:判断当前线程是否是锁线程
  15. // 所以如果存在独占锁,并且锁线程不是当前线程,则尝试失败
  16. // 否则当前步骤成功
  17. if (exclusiveCount(c) != 0 &&
  18. getExclusiveOwnerThread() != current)
  19. return false;
  20. // 高16位解析,获取共享锁数量
  21. int r = sharedCount(c);
  22. // 共享锁最大值判断,
  23. // MAX_COUNT = (1 << SHARED_SHIFT) - 1;
  24. if (r == MAX_COUNT)
  25. throw new Error("Maximum lock count exceeded");
  26. // 按照重入逻辑,如果可以加锁,则是对state+1
  27. // 但是共享锁是对高16位进行操作,所以应该在高16位的基础上加1,
  28. // SHARED_UNIT = (1 << SHARED_SHIFT);
  29. if (compareAndSetState(c, c + SHARED_UNIT)) {
  30. // r为0,表示当前并没有共享锁进入,则初始化当前线程为头线程
  31. if (r == 0) {
  32. firstReader = current;
  33. firstReaderHoldCount = 1;
  34. // 当前线程重入,则对重入此时递增
  35. } else if (firstReader == current) {
  36. firstReaderHoldCount++;
  37. } else {
  38. // 此处表示获取共享锁的线程不是当前锁线程
  39. // 存在新线程尝试获取共享锁,则cachedHoldCounter必定为null
  40. HoldCounter rh = cachedHoldCounter;
  41. if (rh == null || rh.tid != getThreadId(current))
  42. // readHolds集成自ThreadLocal,为每一个新线程分配一个HoldCounter
  43. cachedHoldCounter = rh = readHolds.get();
  44. // 可能存在其他途径创建线程的HoldCounter,这样在readHolds中可能不存在(个人理解)
  45. else if (rh.count == 0)
  46. readHolds.set(rh);
  47. // 初始化完成后,对count递增,表示线程加锁及重入
  48. rh.count++;
  49. }
  50. return true;
  51. }
  52. }
  53. }
  54. \* readHolds.get():此处涉及 ThreadLocal 的初始化部分
  55. // ThreadLocalHoldCounter继承自ThreadLocal
  56. // 泛型表示ThreadLocal为每一个线程分配一个 HoldCounter 对象
  57. // 当前类重写了父类的initialValue()方法,并初始化了一个HoldCounter对象
  58. // 表示 ThreadLocalHoldCounter 默认为每一个线程分配一个已经初始化好的对象
  59. // 每一次get时,如果获取不到线程已经存储的信息,则直接返回一个新对象
  60. static final class ThreadLocalHoldCounter extends ThreadLocal<HoldCounter> {
  61. public HoldCounter initialValue() {
  62. return new HoldCounter();
  63. }
  64. }

2,加锁

  1. \* lock()
  2. public void lock() {
  3. sync.acquireShared(1);
  4. }
  5. public final void acquireShared(int arg) {
  6. if (tryAcquireShared(arg) < 0)
  7. doAcquireShared(arg);
  8. }
  9. \* tryAcquireShared(int unused)
  10. protected final int tryAcquireShared(int unused) {
  11. Thread current = Thread.currentThread();
  12. int c = getState();
  13. // 存在写锁,并且不是当前线程获取,则获取锁失败
  14. // 此处不排除存在写锁,如果存在写锁则写锁为当前线程持有
  15. if (exclusiveCount(c) != 0 &&
  16. getExclusiveOwnerThread() != current)
  17. return -1;
  18. // readerShouldBlock():判断是否存在下一个节点,且下一个节点不是共享节点
  19. int r = sharedCount(c);
  20. if (!readerShouldBlock() &&
  21. r < MAX_COUNT &&
  22. compareAndSetState(c, c + SHARED_UNIT)) {
  23. // 下面为加锁处理
  24. if (r == 0) {
  25. firstReader = current;
  26. firstReaderHoldCount = 1;
  27. } else if (firstReader == current) {
  28. firstReaderHoldCount++;
  29. } else {
  30. HoldCounter rh = cachedHoldCounter;
  31. if (rh == null || rh.tid != getThreadId(current))
  32. cachedHoldCounter = rh = readHolds.get();
  33. else if (rh.count == 0)
  34. readHolds.set(rh);
  35. rh.count++;
  36. }
  37. return 1;
  38. }
  39. // 继续尝试获取共享锁
  40. return fullTryAcquireShared(current);
  41. }
  42. \* fullTryAcquireShared(Thread current)
  43. final int fullTryAcquireShared(Thread current) {
  44. HoldCounter rh = null;
  45. for (;;) {
  46. int c = getState();
  47. // 判断是否独占锁,且不是当前线程
  48. // 当前线程获取独占锁后,可继续获取共享锁
  49. if (exclusiveCount(c) != 0) {
  50. if (getExclusiveOwnerThread() != current)
  51. return -1;
  52. // 存在下一个节点,并且下一个不是共享锁节点,则需要阻塞
  53. } else if (readerShouldBlock()) {
  54. // firstReader表示当前线程,说明正在执行中,默认不阻塞
  55. if (firstReader == current) {
  56. } else {
  57. // 此处判断当前线程是否在执行中,rh.count表示重入
  58. // 如果在执行中,则继续可以获取执行,如果不在执行中,则获取失败
  59. if (rh == null) {
  60. rh = cachedHoldCounter;
  61. if (rh == null || rh.tid != getThreadId(current)) {
  62. rh = readHolds.get();
  63. if (rh.count == 0)
  64. readHolds.remove();
  65. }
  66. }
  67. if (rh.count == 0)
  68. return -1;
  69. }
  70. }
  71. // 最大值判断
  72. if (sharedCount(c) == MAX_COUNT)
  73. throw new Error("Maximum lock count exceeded");
  74. // 获取锁成功
  75. if (compareAndSetState(c, c + SHARED_UNIT)) {
  76. if (sharedCount(c) == 0) {
  77. firstReader = current;
  78. firstReaderHoldCount = 1;
  79. } else if (firstReader == current) {
  80. firstReaderHoldCount++;
  81. } else {
  82. if (rh == null)
  83. rh = cachedHoldCounter;
  84. if (rh == null || rh.tid != getThreadId(current))
  85. rh = readHolds.get();
  86. else if (rh.count == 0)
  87. readHolds.set(rh);
  88. rh.count++;
  89. cachedHoldCounter = rh; // cache for release
  90. }
  91. return 1;
  92. }
  93. }
  94. }
  95. \* readerShouldBlock():存在下一个节点,并且下一个节点不是共享节点,返回true,否则返回false
  96. final boolean readerShouldBlock() {
  97. return apparentlyFirstQueuedIsExclusive();
  98. }
  99. // 此处判断是否存在下一个节点,以及下一个节点是否为共享节点(取反)
  100. final boolean apparentlyFirstQueuedIsExclusive() {
  101. Node h, s;
  102. return (h = head) != null &&
  103. (s = h.next) != null &&
  104. !s.isShared() &&
  105. s.thread != null;
  106. }

3,释放锁

  1. \* unlock()
  2. public void unlock() {
  3. sync.releaseShared(1);
  4. }
  5. public final boolean releaseShared(int arg) {
  6. if (tryReleaseShared(arg)) {
  7. doReleaseShared();
  8. return true;
  9. }
  10. return false;
  11. }
  12. \* tryReleaseShared(int unused)
  13. protected final boolean tryReleaseShared(int unused) {
  14. Thread current = Thread.currentThread();
  15. // 判断当前线程是否firstReader
  16. // 此处条件判断,主要为了递减线程重入次数,如果可以释放,则对关键标识对象置空,帮助GC,并方便后续操作判断
  17. if (firstReader == current) {
  18. // 继续判断firstReaderHoldCount重入次数,如果为1,说明可以彻底释放,重置firstReader
  19. // 不为1,递减即可
  20. if (firstReaderHoldCount == 1)
  21. firstReader = null;
  22. else
  23. firstReaderHoldCount--;
  24. } else {
  25. // 当前线程不是firstReader,则从readHolds中获取,并判断count重入次数
  26. HoldCounter rh = cachedHoldCounter;
  27. if (rh == null || rh.tid != getThreadId(current))
  28. rh = readHolds.get();
  29. int count = rh.count;
  30. // count <=1,同样表示彻底释放,从readHolds中移除
  31. if (count <= 1) {
  32. readHolds.remove();
  33. if (count <= 0)
  34. throw unmatchedUnlockException();
  35. }
  36. --rh.count;
  37. }
  38. for (;;) {
  39. // 获取共享锁的重入次数,并递减,是否为0标识
  40. int c = getState();
  41. int nextc = c - SHARED_UNIT;
  42. if (compareAndSetState(c, nextc))
  43. return nextc == 0;
  44. }
  45. }

五,ReentrantReadWriteLock.WriteLock源码分析

1,尝试加锁

  1. \* tryLock( )
  2. public boolean tryLock( ) {
  3. return sync.tryWriteLock();
  4. }
  5. \* tryWriteLock()
  6. final boolean tryWriteLock() {
  7. Thread current = Thread.currentThread();
  8. int c = getState();
  9. // c不为0,表示存在独占锁或者共享锁
  10. if (c != 0) {
  11. // 获取独占锁重入次数
  12. int w = exclusiveCount(c);
  13. // w为0,说明独占锁为空,则表示存在共享锁,获取锁失败
  14. // w不为0,并且锁线程不是当前线程,说明存在其他线程持有独占锁,获取锁失败
  15. // 此处证明在同一线程下,获取共享锁后,不可获取独占锁
  16. if (w == 0 || current != getExclusiveOwnerThread())
  17. return false;
  18. if (w == MAX_COUNT)
  19. throw new Error("Maximum lock count exceeded");
  20. }
  21. // CAS设置重入状态,设置成功后,添加锁线程为当前线程
  22. if (!compareAndSetState(c, c + 1))
  23. return false;
  24. setExclusiveOwnerThread(current);
  25. return true;
  26. }

2,加锁

  1. \* lock()
  2. public void lock() {
  3. sync.acquire(1);
  4. }
  5. public final void acquire(int arg) {
  6. if (!tryAcquire(arg) &&
  7. acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
  8. selfInterrupt();
  9. }
  10. \* tryAcquire(int acquires):此处尝试加锁与上一步尝试加锁基本一致,只是加了一步判断
  11. protected final boolean tryAcquire(int acquires) {
  12. Thread current = Thread.currentThread();
  13. int c = getState();
  14. int w = exclusiveCount(c);
  15. if (c != 0) {
  16. if (w == 0 || current != getExclusiveOwnerThread())
  17. return false;
  18. if (w + exclusiveCount(acquires) > MAX_COUNT)
  19. throw new Error("Maximum lock count exceeded");
  20. setState(c + acquires);
  21. return true;
  22. }
  23. // writerShouldBlock:判断写锁是否需要阻塞
  24. if (writerShouldBlock() ||
  25. !compareAndSetState(c, c + acquires))
  26. return false;
  27. setExclusiveOwnerThread(current);
  28. return true;
  29. }
  30. \* writerShouldBlock():该方法在非公平锁中默认返回false,再公平锁实现中,进行了AQS队列存在性校验,保证顺序执行
  31. // 非公平锁
  32. final boolean writerShouldBlock() {
  33. return false;
  34. }
  35. // 公平锁
  36. final boolean writerShouldBlock() {
  37. return hasQueuedPredecessors();
  38. }
  39. public final boolean hasQueuedPredecessors() {
  40. Node t = tail;
  41. Node h = head;
  42. Node s;
  43. return h != t &&
  44. ((s = h.next) == null || s.thread != Thread.currentThread());
  45. }

3,释放锁

  1. \* unlock()
  2. public void unlock() {
  3. sync.release(1);
  4. }
  5. public final boolean release(int arg) {
  6. if (tryRelease(arg)) {
  7. Node h = head;
  8. if (h != null && h.waitStatus != 0)
  9. unparkSuccessor(h);
  10. return true;
  11. }
  12. return false;
  13. }
  14. \* tryRelease(int releases)
  15. protected final boolean tryRelease(int releases) {
  16. // 判断当前线程是否锁线程
  17. if (!isHeldExclusively())
  18. throw new IllegalMonitorStateException();
  19. // 获取释放后的独占锁重入次数
  20. int nextc = getState() - releases;
  21. boolean free = exclusiveCount(nextc) == 0;
  22. // 重入次数为0,则释放成功,置空锁线程,
  23. if (free)
  24. setExclusiveOwnerThread(null);
  25. setState(nextc);
  26. return free;
  27. }

发表评论

表情:
评论列表 (有 0 条评论,105人围观)

还没有评论,来说两句吧...

相关阅读