赞
踩
1.CAS(Compare And Swap)是一种思想是一种用来实现线程安全的算法,同时也是一组cpu指令。Compare And Swap这一条指令就能完成比较与交换的组合操作,不会被打断,主要运用在并发编程语句,实现那些不能被打断的数据交换操作,从而避免了多线程情况下,出现不可预知的问题
2.思路:我认为V的值应该是A,如果是的话,那我就把它改成B,如果不是A(说明被别人修改过了),那我就不修改了,避免多人同时修改导致出错
3.CAS有三个操作数:内存值V、预期值A、要修改的值B,当且仅当预期值A和内存值V相同时,才将内存值修改为B,否则什么都不做。最后返回现在的V值
/** * 模拟CAS操作,等价代码 */ public class TwoThreadsCompetition implements Runnable { private volatile int value; public synchronized int compareAndSwap(int expectedValue,int newValue){ int oldValue = value; if (expectedValue == oldValue){ value=newValue; } return oldValue; } public static void main(String[] args) throws InterruptedException { TwoThreadsCompetition r = new TwoThreadsCompetition(); r.value=0; Thread t1 = new Thread(r,"Thread1"); Thread t2 = new Thread(r,"Thread2"); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(r.value); } @Override public void run() { compareAndSwap(0,1); } }
1.乐观锁
2,并发容器,以ConcurrentHashMap为例
3.原子类
以AtomicInteger为例
1.AtomicInteger加载Unsafe工具,用来直接操作内存数据
2.用Unsafe来实现底层操作
3.用volatile修饰value字段,保证可见性
4.getAndAddInt方法分析
5.Unsafe类
① Unsafe是CAS的核心类。Java无法直接访问底层操作系统,而是通过本地(native)方法来访问。不过尽管如此,JVM还是开了一个后门,JDK中有一个类Unsafe,它提供了硬件级别的原子操作
② valueOffset表示的是变量值在内存中的偏移地址,因为Unsafe就是根据内存偏移地址获取数据的原值的,这样我们就能通过unSafe来实现CAS了
在java中是如何利用CAS实现原子性操作
① Unsafe类中的CompareAndSwapInt方法
方法中先想办法拿到变量的value在内存中的地址
通过Atomic::cmpxchg实现原子性的比较和替换,其中参数x是即将更新的值,参数e是原内存中的值,至此,最终完成了CAS的全过程
ABA 问题:
在计算时只是检查值是否相等,并没有检查是否被修改过,利用乐观锁时添加版本号,对比版本号检查。
自旋时间过长:
很长时间的自旋(有些死循环操作),如果在此期间竞争很激烈,锁一直拿不到,消耗CPU资源,对性能消耗很大
解决:
代码层面,破坏掉for死循环,当超过一定时间或者一定次数时,return退出。
使用类似ConcurrentHashMap的方法。当多个线程竞争时,将粒度变小,将一个变量拆分为多个变量,达到多个线程访问多个资源的效果,最后再调用sum把它合起来,能降低CPU消耗,但是治标不治本。
使用JVM能支持处理器提供的pause指令来提升效率。pause指令有两个作用:第一,它可以延迟流水线执行指令(de-pipeline),使CPU不会消耗过多的执行资源,延迟的时间取决于具体实现的版本,在一些处理器上延迟时间是零;第二,它可以避免在循环的时候因内存顺序冲突(Memory Order Violation)而引起CPU流水线被清空,从而提高CPU的实行效率
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。