可重入锁与不可重入锁权衡
观点整理
可重入锁(reentrant)也称为递归锁(recursive),意味着同一个线程可以重复对其加锁。
可重入锁可以看作不可重入锁的超集,除记录持有锁的线程ID外还关联一个计数器,当重复加锁时计数器递增,当计数器为0时释放锁。
C++中std::mutex
是不可重入锁,std::recursive_mutex
是可重入锁。
Windows的CRITICAL_SECTION
是可重入的。
Java里只要以Reentrant开头命名的锁都是可重入锁,而且JDK提供的所有现成的Lock实现类,包括synchronized
关键字锁都是可重入的。
认为不可重入锁更好的一方认为,其能快速暴露设计上的缺陷,方便debug。
David Butenhof(Programming with POSIX Threads的作者)认为:
A correct and well understood design does not require recursive mutexes.(recursive mutexes)
《Linux多线程服务端编程》(陈硕著)认为:
只用非递归的mutex(即不可重入的mutex)。
我还没有遇到过需要使用recursive mutex的情况,我想将来遇到了都可以借助wrapper改用non-recursive mutex,代码只会更清晰。(多线程服务器的常用编程模型)
《C++并发编程实战》第二版(Anthony Williams著)认为:
我们通常可以采取更好的方法(避免使用递归锁):根据这两个公有函数的共同部分,提取出一个新的私有函数,新函数由这两个公有函数调用,而它假定互斥已经被锁住,遂无须重复加锁。经过上面的改良设计,读者可以更进一步地仔细推敲,什么情形应当调用新函数,以及数据在该情形中处于什么状态。
认为可重入锁更好的一方认为,没有一定需要不可重入锁的业务场景。
HBLOG认为:
99%的业务场景用可重入锁就可以了,剩下的1%是什么呢?我也不知道,谁可以在评论里告诉我?(各种锁及其Java实现)