多线程技术内容片段

Scroll Down

读写锁跟互斥锁类似,也是申请锁的时候,如果不能得到满足则阻塞,但读写锁跟互斥锁也有不同,读写锁有3个状态:

已加读锁状态

已加写锁状态

未加锁状态

对应3个状态,读写锁有3个接口:加读锁,加写锁,解锁:

加读锁:如果读写锁处于已加写锁状态,则申请锁的线程阻塞;否则把锁设置为已加读锁状态并成功返回

加写锁:如果读写锁处于未加锁状态,则把锁设置为已加写锁状态并成功返回;否则阻塞

解锁:把锁设置为未加锁状态后返回

读写锁提升了线程的并行度,可以提升吞吐。它可以让多个读线程同时读共享资源,而写线程访问共享资源的时候,其他线程不能执行,所以,读写锁适合对共享资源访问“读大于写”的场合。读写锁也叫“共享互斥锁”,多个读线程可以并发访问同一资源,这对应共享的概念,而写线程是互斥的,写线程访问资源的时候,其他线程无论读写,都不可以进入临界代码区。

考虑一个场景:如果有线程1、2、3共享资源x,读写锁rwlock保护资源,线程1读访问某资源,然后线程2以写的形式访问同一资源x,因为rwlock已经被加了读锁,所以线程2被阻塞,然后过了一段时间,线程3也读访问资源x,这时候线程3可以继续执行,因为读是共享的,然后线程1读访问完成,线程3继续访问,过了一段时间,在线程3访问完成前,线程1又申请读资源,那么它还是会获得访问权,但是写资源的线程2会一直被阻塞。

为了避免共享的读线程饿死写线程,通常读写锁的实现,会给写线程优先权,当然这处决于读写锁的实现,作为读写锁的使用方,理解它的语义和使用场景就够了。

用到 ThreadLocal 的地方,一定要成对 remove,就像开启流之后必须 close 一样,不及时 remove 会出现内存泄漏或数据污染。

建议严格检查 InheritableThreadLocal 的使用场景,如果确实需要(解决父子线程问题),必须检查重写 childValue 方法。