属于悲观锁,有共享资源,需要加锁时,会以独占锁的方式导致其它需要获取锁才能执行的线程挂起,等待持有锁的钱程释放锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronized和ReentrantLock等独占锁就是悲观锁的思想。
多线程并发修改一个值时的实现:
public class SimulatedCAS { //加volatile的目的是利用其happens-before原则,保证线程可见性 private volatile int value; public synchronized int getValue() { return value; } public synchronized int compareAndSwap(int expectedValue, int newValue) { int oldValue = value; if (value == expectedValue) value = newValue; return oldValue; } }
总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。 在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。乐观锁一般会使用版本号机制或CAS算法实现。
public class CasCounter { private SimulatedCAS value; public int getValue() { return value.getValue(); } public int increment() { int oldValue = value.getValue(); while (value.compareAndSwap(oldValue, oldValue + 1) != oldValue) oldValue = value.getValue(); return oldValue + 1; } }
JDK5.0之后加入了java.util.concurrent.atomic 包,其中的AtomicInteger; AtomicLong; AtomicReference; AtomicBoolean 等都是在CAS基础上实现的。
public class AtomicTest { private static AtomicInteger atomicInteger = new AtomicInteger(100); private static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<Integer>(99, 0); public static void main(String[] args) throws InterruptedException { Thread thread1 = new Thread(() -> { atomicInteger.compareAndSet(99, 100); atomicInteger.compareAndSet(100, 99); }); Thread thread2 = new Thread(() -> { try { TimeUnit.SECONDS.sleep(1); }catch (InterruptedException e){ e.printStackTrace(); } boolean b = atomicInteger.compareAndSet(99, 100); System.out.println(b); }); thread1.start(); thread2.start(); thread1.join(); thread2.join(); Thread refT1 = new Thread(() -> { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } atomicStampedReference.compareAndSet(99, 100, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1); atomicStampedReference.compareAndSet(100, 99, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1); }); Thread refT2 = new Thread(() -> { int stamp = atomicStampedReference.getStamp(); System.out.println("before sleep : stamp = " + stamp); // stamp = 0 try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("after sleep : stamp = " + atomicStampedReference.getStamp());//stamp = 1 boolean c3 = atomicStampedReference.compareAndSet(99, 100, stamp, stamp+1); System.out.println(c3); //false }); refT1.start(); refT2.start(); } }
结果如下:
true before sleep : stamp = 0 after sleep : stamp = 2 false
也就是说AtomicInteger更新成功,而AtomicStampedReference更新失败。
以上就是详解java 中的CAS与ABA的详细内容,更多关于java 中的CAS与ABA的资料请关注脚本之家其它相关文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、来自互联网转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系QQ:712375056 进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
Copyright © 2009-2021 56dr.com. All Rights Reserved. 特网科技 特网云 版权所有 珠海市特网科技有限公司 粤ICP备16109289号
域名注册服务机构:阿里云计算有限公司(万网) 域名服务机构:烟台帝思普网络科技有限公司(DNSPod) CDN服务:阿里云计算有限公司 中国互联网举报中心 增值电信业务经营许可证B2
建议您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流浏览器浏览本网站