首页 > 编程语言 > java 线程安全(二)CAS操作

java 线程安全(二)CAS操作

时间:2023-02-28 11:44:58浏览次数:39  
标签:ABA java 变量 CAS 修改 线程 操作

为了把关于线程相关的内容搞清楚,在synchronized一节中有提到CAS这个操作

一、什么是CAS?

CAS,compare and swap的缩写,中文翻译成比较并交换。JDK提供的非阻塞原子性操作,它通过硬件保证了更新操作的原子性。它允许多线程非阻塞地对共享资源进行修改,但是同一时刻只有一个线程可以修改,其他线程并不会阻塞而是重新尝试。

CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。 如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值 。否则,处理器不做任何操作。

二、为什么会有CAS?

一般乐观锁采取的策略。在Java中使用锁不好的地方就是当一个线程没有获得锁,就会导致线程的上下文切换,导致重新调度与开销。而volatile只能保证有序性和可见性,并不能保证原子性。CAS操作保证了原子性。

三、CAS详解

CAS,比较和交换,从语义上是两步操作,但实际上一条CPU指令就能完成。这说明,他是一个原子性操作,要么全做,要么全不做。

JDK的Unsafe类提供了compareAndSwap方法,boolean compareAndSwapLong(Object obj,Long valueOffset,long expect,long update);

参数:对象的内存地址,偏移值,期望的旧值,期望的新值

如果对象 obj中内存偏移量为 valueOffset的变量值为 expect,则使用新的值 update替换旧值 expect。这是处理器提供的一个原子性操作。

CAS经典问题:ABA问题

假如线程1使用CAS修改初始值为A的变量X(X=A),那么线程1首先会获取当前变量X的值(A),然后使用CAS操作尝试修改X的值为B,如果使用CAS修改成功了,那么程序运行一定是正常的吗?其实未必,这是因为有可能在线程1获取到变量X的值A后,在执行CAS之前,线程2使用了CAS修改了变量X值为B,然后又使用了CAS操作使得变量X值为A,虽然线程A执行了CAS操作时X=A,但是这个A已经不是线程1获取到的A了。这就是ABA问题。ABA问题的产生是因为变量的状态值产生了环形转换,就是变量值可以从A到B,也可以B到A,如果变量的值只能朝着一个方向转换,例如A到B,B到C,不构成环路,就不会存在这个问题。JDK中的AtomicStampedReference类给每个变量的状态值都配备了一个时间戳,从而避免了ABA问题。或者是使用版本号,一个数据一个版本号,版本号不同数据值相同,也不会进行修改。

ABA问题会导致什么后果?

摘录自:CAS的ABA问题,ABA问题会导致什么后

对于像库存数据的变化,通常来说,不会对结果造成影响。但是对于栈来说就会有影响。

再看一个堆栈操作的例子:

并发1(上):读取栈顶的元素为“A1”

并发2:进行了2次出栈

并发3:又进行了1次出栈

并发1(下):实施CAS乐观锁,发现栈顶还是“A1”,于是修改为A2

此时会出现系统错误,因为此“A1”非彼“A1”

 

标签:ABA,java,变量,CAS,修改,线程,操作
From: https://www.cnblogs.com/freewsf/p/17163485.html

相关文章

  • python 多线程编程
    多线程编程importtimeimportthreadingdefsing(msg):whileTrue:print(msg)time.sleep(1)defdance(msg):whileTrue:print......
  • oracle锁表,java代码修改方式如下
    selectb.owner,b.object_name,a.session_id,a.locked_modefromv$locked_objecta,dba_objectsbwhereb.object_id=a.object_id;selectb.username,b.sid,b.serial#,l......
  • WPF中的Frozen(冻结)与线程及其他相关问题
    System.Windows.Freezable类(在WindowsBase.dll中)定义一个对象,该对象具有可修改状态和只读(冻结)状态。派生自Freezable的类提供详细的更改通知,可以是不可变的,并且可以进行......
  • 【java】一些基础小知识
    重写重载:重写:是继承时对父类的方法重写该方法内容,方法类型是不变的,即返回类型,方法名字,参数都不变。值得注意的是可以改变权限,只能提高不能降低重载:是一个类中有多个名字......
  • java网络编程-线程池服务端
    上篇文章我们借助线程实现了服务端可以服务多个客户端,但是每次请求进来都创建新线程也是一种很大的资源消耗,线程上下文切换都会影响性能。本次我们继续对服务端进行改造,引......
  • java调用c++的几种方式
    jni类似c#调用c++的方式,定义java端的c++代码接口。packagecrayon.jni;publicclassJNITest{publicnativestaticvoidset(inti);publicna......
  • Java学习笔记12
    正则表达式1.概述​ 在Java中,我们经常需要验证一些字符串,例如:年龄必须是2位的数字、用户名必须是8位长度而且只能包含大小写字母、数字等。正则表达式就是用来验证各种字......
  • 基础Java学习笔记(一)
    学习笔记01两年前学的Java,现在已经忘得差不多了,跟着狂神说Java的视频从头开始学,希望能救一救ww一、JDKJREJVM1.JDKjavadevelopmentkit2.JREjavaRuntimeEnvir......
  • java网络编程-并发服务端
    上次的服务端一次只能接受一个客户端的连接,性能实在堪忧,我们对服务端进行了改造,每接到一个客户端的请求,就新建一个线程,让新线程跟客户端进行交互,主线程可以继续等待其他客......
  • java面试题-列举常见的异常
    面试中经常会被问到,列举几种常见异常。怎么能被这个难倒呢?下面随便列举些,以及触发例子。文章目录​​NullPointerException​​​​ArithmeticException​​​​NumberFor......