接下来几章说的是锁的优化和注意事项问题。
减小锁持有的时间
- 对于在方法执行的过程中有的步骤不需要进行同步,那么就在只需要进行同步的程序中进行加锁。不需要的方法 就不再加锁。
减小锁粒度
- ConcurrentHashMap: 内部进一步的分成若干个 HashMap 。 我们称之为 SEGMENT. 默认情况下 细分为16个段。在进行put()操作之前,该HashMap 总是先得到 段 ,然后在执行put() 操作。
- 但是如果我们需要获得全局锁时,消耗的资源就很多。 比如需要操作的是size方法 。在这个Map中首先会尝试使用无锁的方式来求和,失败之后才会尝试这种加锁的方式。
- 总的来说减少所粒度,就是减少锁定对象的范围。 较少所冲突的可能性,进而提高系统的并发能力。
读写分离代替独占锁
锁分离 : 具体可以看LindedBlockingQueue 代码实现
锁粗化 : 对一系列的操作需要锁的 ,可以减少锁的同步次数。这就是粗化。
锁偏向
- 一个线程获得了锁,那么锁就进入了锁偏向模式。当这个线程再次请求锁的时候就无需再进行同步操作。 使用Java 虚拟机参数-XX: +UseBiasedLocking 开启偏向锁。
轻量级锁
- 如果偏向锁 失败,虚拟机 并不会立即挂起线程。会使用一种优化操作。只是简单的将对象头部作为指针,指向持有锁的线程堆栈的内部,来判断一个线程是否持有对象锁。成功进入临界区,失败的话很容易膨胀成重量锁。
自旋锁
- 锁膨胀后,为了避免在操作系统上挂起,虚拟机还会做最后的努力--自旋锁。进行循环 再去尝试获得锁,如果经过若干次尝试之后还是失败,那么就会在系统上挂起线程。
锁清除
- 锁清除是一种更彻底的锁优化。 通过上下文对不可能存在共享资源竞争的锁进行清除。减少毫无意义的请求锁的时间。
ThreadLocal
- 一个局部的线程变量。 只有当前线程可以访问。
CAS 比较交换
- CAS 包含三个参数, V 表示要更新的变量, E 表示预期值,N表示新值。 只有当V==E 时 才将V的值 设置为N . 如果V值 和E值不同,代表有其他线程已经操作过该值。则当前线程不操作,直接返回真实值即可。
网友评论