1. Synchronized锁优化
jdk 1.6为了减少获得锁和释放锁带来的性能消耗,引入了“偏向锁”和“轻量级锁”。
在JavaSE1.6中,锁一共有4种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态,这几个状态会随着竞争情况逐渐升级。
锁可以升级但不能降级,意味着偏向锁升级成轻量级锁后不能降级成偏向锁。这种锁升级却不能降级的策略,目的是为了提高获得锁和释放锁的效率。
偏向锁:
无锁竞争的情况下为了减少锁竞争的资源开销,引入偏向锁。
轻量级锁:
轻量级锁所适应的场景是线程交替执行同步块的情况。
锁粗化:减少不必要的紧连在一起的unlock,lock操作,将多个连续的锁扩展成一个范围更大的锁。
锁消除:指虚拟机即时编译器在运行时,对一些代码要求同步,但是被检测到不可能存在共享数据竞争的锁进行削除。
适应性自旋:自适应意味着自旋的时间不再固定了,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。如果在同一个锁对象上,自旋等待刚刚成功获得过锁,并且持有锁的线程正在运行中,那么虚拟机就会认为这次自旋也很有可能再次成功,进而它将允许自旋等待持续相对更长的时间,比如100个循环。另一方面,如果对于某个锁,自旋很少成功获得过,那在以后要获取这个锁时将可能省略掉自旋过程,以避免浪费处理器资源。
1.1 锁的优缺点对比
2. CAS
CAS,在Java并发应用中通常指CompareAndSwap或CompareAndSet,即比较并交换。
- CAS是一个原子操作,它比较一个内存位置的值并且只有相等时修改这个内存位置的值为新的值,保证了新的值总是基于最新的信息计算的,如果有其他线程在这期间修改了这个值则CAS失败。CAS返回是否成功或者内存位置原来的值用于判断是否CAS成功。
- JVM中的CAS操作是利用了处理器提供的CMPXCHG指令实现的。
优点:
- 竞争不大的时候系统开销小。
缺点:
- 循环时间长开销大。
- ABA问题。
- 只能保证一个共享变量的原子操作。
3. Java中的锁实现
3.1 队列同步器(AQS)
队列同步器AbstractQueuedSynchronizer(以下简称同步器),是用来构建锁或者其他同步组件的基础框架。
3.1.1 它使用了一个int成员变量表示同步状态。
3.1.2 通过内置的FIFO双向队列来完成获取锁线程的排队工作。
- 同步器包含两个节点类型的应用,一个指向头节点,一个指向尾节点,未获取到锁的线程会创建节点线程安全(compareAndSetTail)的加入队列尾部。同步队列遵循FIFO,首节点是获取同步状态成功的节点。
- 未获取到锁的线程将创建一个节点,设置到尾节点。
- 首节点的线程在释放锁时,将会唤醒后继节点。而后继节点将会在获取锁成功时将自己设置为首节点。如下图所示:
3.1.3 独占式/共享式锁获取
独占式:有且只有一个线程能获取到锁,如:ReentrantLock;
共享式:可以多个线程同时获取到锁,如:CountDownLatch;
独占式
- 每个节点自旋观察自己的前一节点是不是Header节点,如果是,就去尝试获取锁。
- 独占式锁获取流程:
共享式:
- 共享式与独占式的区别:
- 共享锁获取流程:
参考文章:https://www.cnblogs.com/barrywxx/p/8678698.html