ReentrantReadWriteLock实现
2015-08-14 21:07
274 查看
读写锁顾名思义就是提供了一个读锁、一个写锁,其中读锁是共享锁,写锁是独占锁。
读锁同时可以有多个线程获取,获取的前提是没有其他线程的写锁(当然还有同时并发数限制,不过普通java进程也不会起那么多的线程);
写锁同时只能有一个线程获取,获取的前提是没有读锁和非本线程的写锁
ReentrantReadWriteLock 通过state字段的高低位分别控制读锁和写锁,低16位表示写锁,高16位表示读锁
读锁获取流程:
查看锁有没有被写锁占有,如果被写锁占有且占有线程不是当前线程,获取锁失败;
查看是否可以应该被阻塞,这里分两种情况:1)公平锁,如果有线程在排队,则获取锁失败;2)非公平锁,如果排队线程中的第一个是独占锁,则获取锁失败,否则插队(写锁的优先级还是稍高一点,不然读锁的请求量大时,写锁可能永远被阻塞);
如果共享锁的获取数量没有达到上限,尝试通过CAS修改state获取锁;
如果CMS返回成功,则成功得到锁,然后做一些计数。
读锁释放流程:
修改计数,并不停尝试修改state,直到成功;
然后唤醒队列中的线程;
唤醒的是共享线程,共享线程会继续尝试唤醒下一个共享线程,然后下一个共享线程继续....;如果唤醒的是独占线程,独占线程就会直接去尝试抢占锁。
写锁获取流程:
查看锁状态,如果已经被读锁获取,则失败;
如果被写锁独占,但是独占的线程不是当前线程,则失败;是当前线程,直接重入;
判断是否应该被阻塞,这里也是两种情况:1)公平锁,跟读锁一样,如果有排队的,老老实实排队;2)非公平锁,直接抢占;
上面都OK了,尝试修改state,获取成功后,修改独占线程。
写锁释放流程:
写锁释放很简单,因为是线程独占的,所以直接修改state,然后去队列里唤醒线程;
然后唤醒的线程操作同上。
注:
只有独占锁的线程可以重入,所以线程获得写锁之后可以继续重入;
而获得读锁之后接着去取写锁会被永远阻塞,读锁是共享的,而且没有记录所有共享的线程,上面的流程可以看出获取写锁的时候只要存在读锁,就会失败,所以线程不释放自己的读锁就永远获取不到写锁。
当然,获取读锁之后是可以再次获取读锁的,这也不算是重入,而是线程与自己共享。
读锁同时可以有多个线程获取,获取的前提是没有其他线程的写锁(当然还有同时并发数限制,不过普通java进程也不会起那么多的线程);
写锁同时只能有一个线程获取,获取的前提是没有读锁和非本线程的写锁
ReentrantReadWriteLock 通过state字段的高低位分别控制读锁和写锁,低16位表示写锁,高16位表示读锁
读锁获取流程:
查看锁有没有被写锁占有,如果被写锁占有且占有线程不是当前线程,获取锁失败;
查看是否可以应该被阻塞,这里分两种情况:1)公平锁,如果有线程在排队,则获取锁失败;2)非公平锁,如果排队线程中的第一个是独占锁,则获取锁失败,否则插队(写锁的优先级还是稍高一点,不然读锁的请求量大时,写锁可能永远被阻塞);
如果共享锁的获取数量没有达到上限,尝试通过CAS修改state获取锁;
如果CMS返回成功,则成功得到锁,然后做一些计数。
读锁释放流程:
修改计数,并不停尝试修改state,直到成功;
然后唤醒队列中的线程;
唤醒的是共享线程,共享线程会继续尝试唤醒下一个共享线程,然后下一个共享线程继续....;如果唤醒的是独占线程,独占线程就会直接去尝试抢占锁。
写锁获取流程:
查看锁状态,如果已经被读锁获取,则失败;
如果被写锁独占,但是独占的线程不是当前线程,则失败;是当前线程,直接重入;
判断是否应该被阻塞,这里也是两种情况:1)公平锁,跟读锁一样,如果有排队的,老老实实排队;2)非公平锁,直接抢占;
上面都OK了,尝试修改state,获取成功后,修改独占线程。
写锁释放流程:
写锁释放很简单,因为是线程独占的,所以直接修改state,然后去队列里唤醒线程;
然后唤醒的线程操作同上。
注:
只有独占锁的线程可以重入,所以线程获得写锁之后可以继续重入;
而获得读锁之后接着去取写锁会被永远阻塞,读锁是共享的,而且没有记录所有共享的线程,上面的流程可以看出获取写锁的时候只要存在读锁,就会失败,所以线程不释放自己的读锁就永远获取不到写锁。
当然,获取读锁之后是可以再次获取读锁的,这也不算是重入,而是线程与自己共享。
相关文章推荐
- nyoj 14 会场安排问题
- SQLServer With As 用法
- 129. Sum Root to Leaf Numbers
- JavaScript类型检测汇总
- 添加多盟SDK 库函数
- JDBC入门try/catch型
- 【bugfree】安装
- 用dfs序维护树结构
- 【 LightOJ - 1094】Farthest Nodes in a Tree(求树的直径)链式向前星 + DFS or BFS
- 为什么我还不推荐内存中OLTP给用户
- python菜鸟日记7
- UVALive 5840 数学题
- ASP入门(十)-Session对象
- win10和office2013激活
- 黑马程序员 多线程
- 继承与base
- 一个测试 unix 时间戳的程序
- 《算法导论》第一讲
- 动态规划算法
- 如何安装xampp