java cas机制_Java CAS机制详解

CAS目的:

在多线程中为了保持数据的准确性,避免多个线程同时操作某个变量,很多情况下利用关键字synchronized实现同步锁,使用synchronized关键字修可以使操作的线程排队等待运行,可以说是一种悲观策略,认为线程会修改数据,所以开始就把持有锁的线程锁住,其他线程只能是挂起状态,等待锁的释放,所以同步锁带来了问题:

主要的效率问题:在线程执行的时候,获得锁的线程在运行,其他被挂起的线程只能等待着持有锁的线程释放锁才有机会运行(现在JVM可能根据持有锁的时间来操作线程是否是被挂起还是自旋等待),在效率上都浪费在等待上。很可能这种锁是没有必要的,其他线程没有修改数据。在很多的线程切换的时候,由于有同步锁,就要涉及到锁的释放,加锁,这又是一个很大的时间开销。这里涉及到操作系统上的知识,关于线程之间的切换(被挂起和恢复)中间还要经历中断,时间片等等。

上面说了这么多,现在我们追求的是一种效率高,还要保证数据的安全的一种方法。

与锁(阻塞机制)的方式相比有一种更有效地方法,非阻塞机制,同步锁带来了线程执行时候之间的阻塞,而这种非阻塞机制在多个线程竞争同一个数据的时候不会发生阻塞的情况,这样在时间上就可以节省出很多的时间。

想到这里,知道volatile的可能会想到用volatile,使用volatile不会造成阻塞,volatile保证了线程之间的内存可见性和程序执行的有序性可以说已经很好的解决了上面的问题,但是一个很重要的问题就是,volatile不能保证原子性,对于复合操作,例如i++这样的程序包含三个原子操作:取指,增加,赋值。在《Java并发编程实战》这本书上有这样的一句话:变量的新值依赖于旧值时就不能使用volatile变量。实际上就是说的类似于i++这样的操作。具体详见:volatile关键字解析

什么是CAS:

现在采取的是CAS(Compare And Swap比较和交换)解决了volatile不能保证原子性。CAS通常比锁定要快得多,但这取决于争用的程度。因为如果读取和比较之间的值发生变化,CAS可能会强制重试,所以不能说某个方法就是绝对的好。CAS的主要问题是编程比锁定更困难。还好jdk提供了一些类用于完成基本的操作。

CAS主要包含三个操作数,内存位置V,进行比较的原值A,和新值B。当位置V的值与A相等时,CAS才会通过原子方式用新值B来更新V,否则不会进行任何操作。无论位置V的值是否等于A,都将返回V原有的值。通俗点说:我认为V地址的值应该是A,如果是,V地址的值更新为B,否则不修改并告诉V的值实际为多少(无论如何这个值都会通知到V)。上面说到了同步锁 是一种悲观策略,CAS是一种乐观策略,每次都开放自己,不用担心其他线程会修改变量等数据,如果其他线程修改了数据,那么CAS会检测到并利用算法重新计算。CAS也是同时允许一个线程修改变量,其他的线程试图修改都将失败,但是相比于同步锁,CAS对于失败的线程不会将他们挂起,他们下次仍可以参加竞争,这也就是非阻塞机制的特点。

下面用代码简单的实现CAS原理:

/**

* Created with IDEA

*

* @author DuzhenTong

* @Date 2018/2/1

* @Time 11:52

*/

public class SimpleCAS {

private int value;

public SimpleCAS(int value) {

this.value = value;

}

public synchronized int get(){

return value;

}

public synchronized int compareAndSwap(int expectedValue, int newValue){

int oldValue = value;//获取旧值

if(oldValue == expectedValue){//如果期望值与当前V位置的值相同就给予新值

value = newValue;

}

return oldValue;//返回V位置原有的值

}

public synchronized boolean compareAndSet(int expectedValue, int newValue){

return (expectedValue == compareAndSwap(expectedValue, newValue));

}

public static void main(String[] args) {

SimpleCAS simpleCAS = new SimpleCAS(3);

simpleCAS.compareAndSet(5, 10);

System.out.println(simpleCAS.get());//3

SimpleCAS simpleCAS1 = new SimpleCAS(1);

simpleCAS1.compareAndSet(1, 6);

System.out.println(simpleCAS1.get());//6

}

}

从运行结果可以看出代码的原理:设置一个初始值(内存位置),期望值和新值进行比较,如果期望值和初始值一致,返回新值,否则返回初始值。意思是你在修改在一个变量A,假如它原来的值是3,所以你预期它是3,如果在你修改的时候,它被别的线程更新为5,那么就不符合你的预期,你的修改也不会生效

从Java5开始引入了底层的支持,在这之前需要开发人员编写相关的代码才可以实现CAS。在原子变量类Atomic***中(例如AtomicInteger、AtomicLong)可以看到CAS操作的代码,在这里的代码都是调用了底层(核心代码调用native修饰的方法)的实现方法。在AtomicInteger源码中可以看getAndSet方法和compareAndSet方法之间的关系,compareAndSet方法调用了底层的实现,该方法可以实现与一个volatile变量的读取和写入相同的效果。在前面说到了volatile不支持例如i++这样的复合操作,在Atomic***中提供了实现该操作的方法。JVM对CAS的支持通过这些原子类(Atomic***)暴露出来,供我们使用。

CAS带来的问题:

ABA问题:CAS在操作的时候会检查变量的值是否被更改过,如果没有则更新值,但是带来一个问题,最开始的值是A,接着变成B,最后又变成了A。经过检查这个值确实没有修改过,因为最后的值还是A,但是实际上这个值确实已经被修改过了。为了解决这个问题,在每次进行操作的时候加上一个版本号,每次操作的就是两个值,一个版本号和某个值,A——>B——>A问题就变成了1A——>2B——>3A。在jdk中提供了AtomicStampedReference类解决ABA问题,用Pair这个内部类实现,包含两个属性,分别代表版本号和引用,在compareAndSet中先对当前引用进行检查,再对版本号标志进行检查,只有全部相等才更新值。

时间问题:看起来CAS比锁的效率高,从阻塞机制变成了非阻塞机制,减少了线程之间等待的时间。每个方法不能绝对的比另一个好,在线程之间竞争程度大的时候,如果使用CAS,每次都有很多的线程在竞争,而锁可以避免这些状况,相反的情况,如果线程之间竞争程度小,使用CAS是一个很好的选择。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/427164.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

「一本通 4.1 练习 2」简单题

题目描述 题目来源:CQOI 2006 有一个 n 个元素的数组,每个元素初始均为 0。有 m 条指令,要么让其中一段连续序列数字反转——0 变 1,1变 0(操作 1),要么询问某个元素的值(操作 2&…

定时器取数据时实时进来的数据_Redis-数据淘汰策略amp;持久化方式(RDB/AOF)amp;Redis与Memcached区别...

Redis与Memcached区别: 两者都是非关系型数据库。主要有以下不同: 数据类型: Memcached仅支持字符串类型。 redis支持:String,List,set,zset,hash 可以灵活的解决问题。 数据持久化: Memcached不支持持久化。 Redis采…

linux 下建立多个tomcat

第一步:复制,解压 将准备好的tomcat压缩包复制到你准备安装的目录,我的tomcat压缩包名字是tomcat.tar.gz,我的安 装目录是 /usr/java/tomcat 第二步:解压tomcat [rootaliServer tomcat]# tar -xvf tomcat.tar.gz 第三步&#xff…

java apply 函数_Js(Javascript)中的apply方法的使用

Function.apply(obj,args)方法能接收两个参数,简单说apply方法作用就是给类或方法中的this赋值。所以学会这个方法首先要知道this的作用。(this的用法可以看一下这个链接:http://www.cjavapy.com/article/8/ )obj:这个对象将代替Function类里…

linux iptables配置

1 iptables默认系统自带 setup 2重启防火墙 /etc/init.d/iptables restart 3接受端口 Vi /etc/sysconfig/iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT 4 #配置,禁止进,允许出,允许回环网卡 iptables -P I…

memcpy函数_[PART][BUG][MSVCRT][C][CCF NOI1097] 关于memcpy的坑

[Incompleted]CCF NOI1097 试题,本人的源码:Ubuntu Pastebin​paste.ubuntu.comUbuntu PastebinUbuntu Pastebin: SourceCodebyJulianDroid​paste.ubuntu.com满分代码:https://blog.csdn.net/tigerisland45/article/details/71038551​blog.…

Bugku杂项-convert

一进去就发现一堆二进制数,然后考虑怎么才能把这个和隐写扯上关系。首先,二进制我们肉眼就是看不懂再说什么的,这里就想到了转换,再联想上hex将原始数据转化为16进制。我们可以先把2进制转化为16进制,然后再放到hex上看…

tomcat:Cannot find /usr/local/tomcat1/bin/setclasspath.sh

首先看下报错代码: Cannot find /usr/local/tomcat1/bin/setclasspath.sh This file is needed to run this program这个可能是没有在 /etc/profile 中配置环境,这是第一种可能;如果是这种情况的话,可以这样做:vi /etc/profile 并…

在java中柱状图代码_我在java中编写了个柱状图,可运行了,我想让柱状图在JSP页面中显示,请问有什么方法么?谢谢。...

h1,h2 代表了柱形图的高度你可以这样试一试function createImgItem(count){var divdocument.createElement("");var imgdocument.createElement("");img.src"getCertReviewInfoImg.jspx?perCertId${perCertId}&reviewIndex"count;div.appen…

图解cacti简单使用

1登录 admin admin 2点击devices localhost 3进入配置保存 4保存 http服务要启动哦 5一步步做 6graph tree 7执行/usr/bin/php /var/www/html/cacti/poller.php 8如果时间设置错误去php.ini里面修改时间 YSTEM STATS: Time:0.4759 Method:cmd.php Processes:1 Threads:N/…

AFNetworking 3.0源码阅读 - AFURLResponseSerialization

这次来说一下AFURLResponseSerialization这个HTTP响应类。 定义了一个协议,该协议返回序列化后的结果。后续的AFHTTPResponseSerializer以及他的子类都遵循了该协议 该类内有很多子类定义,这里借用一张图来展示,之后一个一个来说。 我们先来看…

python3纵向输出字符串_Python 3.x 格式化输出字符串 % format 笔记

python格式化字符串有%和{}两种 字符串格式控制符.字符串输入数据格式类型(%格式操作符号)%%百分号标记%c字符及其ASCII码%s字符串%d有符号整数(十进制)%u无符号整数(十进制)%o无符号整数(八进制)%x无符号整数(十六进制)%X无符号整数(十六进制大写字符)%e浮点数字(科学计数法)%…

linux 下tomcat服务每天定时启动

1l先准备一个脚本 #!/bin/sh #./etc/profile export JAVA_HOME/usr/java/jdk1.6.0_45 sh /home/tomcat-bingchuang/bin/shutdown.sh sleep 60s sh /home/tomcat-bingchuang/bin/startup.sh 2放置到如上/home/ tomcat-bingchuang/bin/目录下 赋予777权限 并在linux里面设置…

Swordsman

ps&#xff1a;比赛的时候想到了做法&#xff0c;k次排序&#xff0c;然后每次消去能消的。。。然而这种做法是错误的&#xff0c;神奇的是测试案例中排在奇数的案例会WA&#xff0c;排在偶数的案例都过了&#xff0c;被注释的代码会T. #include<bits/stdc.h> #define UL…

java socket编程聊天室_Java Socket通信之聊天室功能

Java Socket通信之聊天室功能发布时间&#xff1a;2020-10-17 14:36:00来源&#xff1a;脚本之家阅读&#xff1a;73作者&#xff1a;LY_624本文实例为大家分享了Java Socket聊天室功能的具体代码&#xff0c;供大家参考&#xff0c;具体内容如下Client.javaimport java.io.*;i…

python计算数组元素的和_python中数组的运算

Python中进行数组的运算需要调用NumPy包。其官网是&#xff1a;http://www.numpy.org/​www.numpy.orgNumPy是Python语言的一个扩充程序库。它支持高级大量的维度数组与矩阵运算&#xff0c;此外也针对数组运算提供大量的数学函数库。Numpy内部解除了CPython的GIL(全局解释器锁…

linux mysql数据库定时备份

1在linux上面创建一个文件夹&#xff0c;并且进行备份 cd /home mkdir backup cd backup 2创建一个脚本 Vi imaginebase.sh #!/bin/bash mysqldump -uroot -ppassword01! imaginebase > /home/backup/imaginebase_KaTeX parse error: Expected group after _ at position 1…

[NOI2014] 起床困难综合症

水题的题解也水...... 原题链接&#xff1a;洛谷 P2114 [NOI2014]起床困难综合症 位运算每一位之间互不干扰。 经过所有门之后每一位不外乎四种结果&#xff1a;一定是0&#xff0c;一定是1&#xff0c;不变或取反。 按位枚举&#xff0c;贪心即可。 对于不变的&#xff0c;我们…

java调用webroot下的文件_JAVA 访问WebRoot下的目录文件

/*** 获取到webroot里面的数据*/java.net.URL url2 classLoader.getResource("");String ROOT_CLASS_PATH url2.getPath() "/";File rootFile new File(ROOT_CLASS_PATH);String WEB_INFO_DIRECTORY_PATH rootFile.getParent() "/";File w…

统计一行文本的单词个数_word操作技巧:不同情况的文字统计方法

最近有朋友询问&#xff0c;如何快速统计出Word文档的字数&#xff1f;这个问题其实非常简单&#xff0c;但往往是这种最简单的知识容易被大家忽视&#xff0c;因此造成困扰。所以&#xff0c;今天我们将为大家详细介绍几种Word统计文档字数的方法&#xff0c;希望能帮助到你&a…