具体CAS操作实现(无锁算法)

具体CAS操作

上一篇讲述了CAS机制,这篇讲解CAS具体操作.

什么是悲观锁、乐观锁?在java语言里,总有一些名词看语义跟本不明白是啥玩意儿,也就总有部分面试官拿着这样的词来忽悠面试者,以此来找优越感,其实理解清楚了,这些词也就唬不住人了。

  • synchronized是悲观锁,这种线程一旦得到锁,其他需要锁的线程就挂起的情况就是悲观锁。
  • CAS操作的就是乐观锁,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。
那么问题来了,什么是CAS操作?

CAS是Compare-and-swap(比较与替换)的简写,是一种有名的无锁算法,在java中,我们主要分析Unsafe类,因为所有的CAS操作都是它来实现的,而在Unsafe类中这些方法也都是native方法

    public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);?    public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);?    public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);

看到上面的解释是不是索然无味,查找了很多资料也没完全弄明白,通过几次验证后,终于明白,最终可以理解成一个无阻塞多线程争抢资源的模型。先上代码

package com.company.reentrantLock;?import java.util.concurrent.atomic.AtomicBoolean;

public class AtomicBooleanTest implements Runnable{    public static AtomicBoolean exits = new AtomicBoolean(true);    public static void main(String[] args) {        AtomicBooleanTest abd = new AtomicBooleanTest();        Thread t1 = new Thread(abd);        Thread t2 = new Thread(abd);        t1.start();        t2.start();    }?    @Override    public void run() {        System.out.println("begin run");        System.out.println("real " + exits.get());        if(exits.compareAndSet(true,false)){            System.out.println(Thread.currentThread().getName() + "  " + exits.get() );            exits.set(true);        }else{            run();        }    }}

输出结果:

begin runreal trueThread-1  falsebegin runreal trueThread-0  false

这里无论怎么运行,Thread-1、Thread-0都会执行if=true条件,而且还不会产生线程脏读脏写,这是如何做到的了,这就用到了我们的compareAndSet(boolean expect,boolean update)方法,先上图简单讲解下程序原理,然后再分析compareAndSet作用。

Paste_Image.png

这个图中重最要的是compareAndSet(true,false)方法要拆开成compare(true)方法和Set(false)方法理解,是compare(true)是等于true后,就马上设置共享内存为false,这个时候,其它线程无论怎么走都无法走到只有得到共享内存为true时的程序隔离方法区。 但是这种得不到状态为true时使用递归算法是很耗cpu资源的,所以一般情况下,都会有线程sleep。

总结

这篇文章并没有展开讲compareAndSet底层调用的是unsafe.compareAndSwapInt方法,因为这是native方法,很多人都会展开找源码,最后也只找到是调用CPU方法,没讲到具体用法,如果只用compareAndSet(true,false)举例则更加简单。 这种无阻塞式的多线程操作数据,在大并发情况下,是一笔非常可观的性能提升,所以,如果在大并发或多线程性能要求高的情况下有更加好的技术选型,可以参考这种底层实现。

原文地址:https://www.cnblogs.com/pingping-joe/p/10606616.html

时间: 2024-08-11 07:19:03

具体CAS操作实现(无锁算法)的相关文章

锁、CAS操作和无锁队列的实现

https://blog.csdn.net/yishizuofei/article/details/78353722 锁的机制 锁和人很像,有的人乐观,总会想到好的一方面,所以只要越努力,就会越幸运:有的人悲观,总会想到不好的一方面,患得患失,所以经常会做不好事.我一直把前一个当作为我前进的动力和方向,快乐充实的过好每一天. 常用的锁机制也有两种: 1.乐观锁:假设不会发生并发冲突,每次不加锁而去完成某项操作,只在提交操作时,检查是否违反数据完整性.如果因为冲突失败就继续重试,直到成功为止.而乐

无锁算法CAS 概述

无锁算法CAS 概述 JDK5.0以后的版本都引入了高级并发特性,大多数的特性在java.util.concurrent包中,是专门用于多线并发编程的,充分利用了现代多处理器和多核心系统的功能以编写大规模并发应用程序.主要包含原子量.并发集合.同步器.可重入锁,并对线程池的构造提供了强力的支持. 原子量是定义了支持对单一变量执行原子操作的类.所有类都有get和set方法,工作方法和对volatile变量的读取和写入一样.并发集合是原有集合框架的补充,为多线程并发程序提供了支持.主要有:Block

非阻塞同步算法与CAS(Compare and Swap)无锁算法

CAS无锁算法 要实现无锁(lock-free)的非阻塞算法有多种实现方法,其中CAS(比较与交换,Compare and swap)是一种有名的无锁算法.CAS, CPU指令,在大多数处理器架构,包括IA32.Space中采用的都是CAS指令,CAS的语义是"我认为V的值应该为A,如果是,那么将V的值更新为B,否则不修改并告诉V的值实际为多少",CAS是项乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起

CAS原子操作实现无锁及性能分析

Author:Echo Chen(陈斌) Email:[email protected] Blog:Blog.csdn.net/chen19870707 Date:Nov 13th, 2014 最近在研究nginx的自旋锁的时候,又见到了GCC CAS原子操作,于是决定动手分析下CAS实现的无锁到底性能如何,网上关于CAS实现无锁的文章很多,但少有研究这种无锁的性能提升的文章,这里就以实验结果和我自己的理解逐步展开. 1.什么是CAS原子操作 在研究无锁之前,我们需要首先了解一下CAS原子操作-

Compare And Swap(CAS)实现无锁多生产者

1.CAS 原理 compare and swap,解决多线程并行情况下使用锁造成性能损耗的一种机制,CAS操作包含三个操作数--内存位置(V).预期原值(A)和新值(B).如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值.否则,处理器不做任何操作.无论哪种情况,它都会在CAS指令之前返回该位置的值.CAS有效地说明了"我认为位置V应该包含值A:如果包含该值,则将B放到这个位置:否则,不要更改该位置,只告诉我这个位置现在的值即可. 当同时存在读写线程时,默认情况下是不保证线

【DPDK】【ring】从DPDK的ring来看x86无锁队列的实现

[前言] 队列是众多数据结构中最常见的一种之一.曾经有人和我说过这么一句话,叫做“程序等于数据结构+算法”.因此在设计模块.写代码时,队列常常作为一个很常见的结构出现在模块设计中.DPDK不仅是一个加速网络IO的框架,其内部还提供众多的功能组件,rte_ring就是DPDK内部提供的一种无锁队列,本篇文章将从使用的角度出发阐述DPDK的ring怎么用?在怎么用的角度上再来阐述ring无锁的实现,最后将探讨实现无锁队列的关键以及在不通平台上如何实现,本文将会探讨x86平台下无锁队列的实现. 权当抛

面试必备:CAS无锁机制

CAS无锁机制原理,面试高频问题之一,其实,日常开发中并不会直接使用CAS无锁机制,都是通过一系列封装好的工具类来使用, 说不定面试官不提问,都不知道有这么个东西存在. 1.能说一下你对CAS的理解吗? 参考回答: 通常我们提到保证多线程安全,会想到三种方式,一是使用Synchronize关键字,但是有个问题就是,使用了Synchronize加锁后的多线程相当于串行,执行效率并不是太高,所以在高并发场景下,使用第二种方式Lock锁,Lock锁要比使用Synchronize关键字在性能上有极大的提

加锁并发算法 vs 无锁并发算法

Heinz Kabutz 在上周举办了一次成功 JCrete研讨会,我在会上参加了对一种新的 StampedLock(于JSR166中 引入) 进行的评审.StampedLock (邮戳锁) 旨在解决系统中共享资源的争用问题.在一个系统中,如果多个需要读写某一共享状态的程序并发访问这个共享对象时,争用问题就产生了.在设计 上,StampedLock 试图通过一种“乐观读取”的方式来减小系统开销,从而提供比 ReentrantReadWriteLock(重入读写锁) 更好的性能. 在评审过程中,我

无锁机制实现并发访问

对于并发控制而言, 锁是一种悲观的策略.它总是假设每一次的临界区操作会产生冲突,因此,必须对每次操作都小心翼翼.如果有多个线程同时需要访问临界区资源,就宁可牺牲性能让线程进行等待,所以说锁会阻塞线程执行. 而无锁是一种乐观的策略,它会假设对资源的访问是没有冲突的.既然没有冲突,自然不需要等待,所以所有的线程都可以在不停顿的状态下持续执行.那遇到冲突怎么办呢?无锁的策略使用一种叫做比较交换的技术(CAS Compare And Swap)来鉴别线程冲突,一旦检测到冲突产生,就重试当前操作直到没有冲