【Java_多线程并发编程】JUC原子类——原子类中的volatile变量和CAS函数
JUC中的原子类是依靠volatile变量和Unsafe类中的
CAS函数实现的。
1. volatile变量的特性
- 内存可见性(当一个线程修改volatile变量的值后,另一个线程就可以实时看到此变量的更新值,也可以理解为敏感性)
- 禁止指令重排(位于volatile变量之前的变量执行先于volatile变量执行,volatile之后的变量执行在volatile变量之后)
2. CAS函数保证数据更新的原子性
CAS是Unsafe 类中定义的函数,它只有如下三种形式:
public final native boolean compareAndSwapInt(Object paramObject, long paramLong, int paramInt1, int paramInt2); public final native boolean compareAndSwapLong(Object paramObject, long paramLong1, long paramLong2, long paramLong3);
public final native boolean compareAndSwapObject(Object paramObject1, long paramLong, Object paramObject2, Object paramObject3);
我们发现Unsafe类只提供了3种CAS方法:compareAndSwapInt、compareAndSwapLong和compareAndSwapObject,且都是native方法
AtomicBoolean 源码解析
public class AtomicBoolean implements java.io.Serializable {
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset; static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicBoolean.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
} private volatile int value; public AtomicBoolean(boolean initialValue) {
value = initialValue ? 1 : 0;
}
public final boolean compareAndSet(boolean expect, boolean update) {
int e = expect ? 1 : 0;
int u = update ? 1 : 0;
return unsafe.compareAndSwapInt(this, valueOffset, e, u);
}
...
}
从AtomicBoolean源码,发现它底层也是使用volatile类型的int 变量,跟AtomicInteger 实现方式一样,只不过是把Boolean转换成 0和1进行操作。
所以原子更新char、float和double变量也可以转换成int 或long来实现CAS的操作。
2.1 CAS的优点
1. CAS即为Compare-And-Swap,是一条CPU的原子指令。CAS操作需要输入两个数值,一个是读取到变量的旧值和一个新值,在操作期间首先比较变量的旧值与当前值是否一致,若一致则更新成新值,若不一致则重复上述操作直到成功为止。
2. CAS操作是原子性的,所以多线程并发中使用CAS更新数据,就可以不使用独占锁。独占锁是一种悲观锁,synchronized就是一种独占锁,会导致其它所有需要锁的线程挂起,等待持有锁的线程释放锁。而另一个更加有效的锁就是乐观锁。所谓乐观锁就是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止,乐观锁用到的机制就是CAS,如果不使用CAS,在高并发下,多线程同时修改一个变量的值我们需要synchronized加锁(可能有人说可以用Lock加锁,Lock底层的AQS也是基于CAS进行获取锁的)。
3.相信sql大家都熟悉,类似sql中的条件更新一样:update set id=3 from table where id=2。因为单条sql执行具有原子性,如果有多个线程同时执行此sql语句,只有一条能更新成功。
2.2 CAS的缺点
1.ABA问题。因为CAS需要在操作值的时候检查下值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。ABA问题的解决思路就是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么A-B-A 就会变成1A-2B-3A。
从Java1.5开始JDK的atomic包里提供了一个类AtomicStampedReference来解决ABA问题。这个类的compareAndSet方法作用是首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。
2. 循环时间长开销大。自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销。
【Java_多线程并发编程】JUC原子类——原子类中的volatile变量和CAS函数的更多相关文章
- 【Java_多线程并发编程】基础篇—Thread类中start()和run()方法的区别
1. start() 和 run()的区别说明 start()方法: 它会启动一个新线程,并将其添加到线程池中,待其获得CPU资源时会执行run()方法,start()不能被重复调用. run()方法 ...
- 【Java_多线程并发编程】JUC原子类——AtomicLong原子类
1. AtomicLong是基本原子类中的一种 AtomicLong是对长整形进行原子操作. 1.1 AtomicLong类的函数列表 // 构造函数 AtomicLong() // 创建值为init ...
- 【Java_多线程并发编程】JUC原子类——4种原子类
根据修改的数据类型,可以将JUC包中的原子操作类可以分为4种,分别是: 1. 基本类型: AtomicInteger, AtomicLong, AtomicBoolean ;2. 数组类型: Atom ...
- 【Java_多线程并发编程】基础篇—线程状态及实现多线程的两种方式
1.Java多线程的概念 同一时间段内,位于同一处理器上多个已开启但未执行完毕的线程叫做多线程.他们通过轮寻获得CPU处理时间,从而在宏观上构成一种同时在执行的假象,实质上在任意时刻只有一个线程获得C ...
- 【Java_多线程并发编程】基础篇——synchronized关键字
1. synchronized同步锁的原理 当我们调用某对象的synchronized方法或代码块时,就获取了该对象的同步锁.例如,synchronized(obj)就获取了“obj这个对象”的同步锁 ...
- 【Java_多线程并发编程】基础篇——线程状态扭转函数
1. wait() sleep() yield() join()用法与区别 本文提到的当前线程是指:当前时刻,获得CPU资源正在执行的线程. 1.1 wait()方法 wait()方法定义在Objec ...
- Java 多线程并发编程一览笔录
Java 多线程并发编程一览笔录 知识体系图: 1.线程是什么? 线程是进程中独立运行的子任务. 2.创建线程的方式 方式一:将类声明为 Thread 的子类.该子类应重写 Thread 类的 run ...
- Java 多线程并发编程
导读 创作不易,禁止转载! 并发编程简介 发展历程 早起计算机,从头到尾执行一个程序,这样就严重造成资源的浪费.然后操作系统就出现了,计算机能运行多个程序,不同的程序在不同的单独的进程中运行,一个进程 ...
- Java 多线程 并发编程
一.多线程 1.操作系统有两个容易混淆的概念,进程和线程. 进程:一个计算机程序的运行实例,包含了需要执行的指令:有自己的独立地址空间,包含程序内容和数据:不同进程的地址空间是互相隔离的:进程拥有各种 ...
随机推荐
- 51Nod 1098 最小方差 (数论)
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; ty ...
- ios 微信登录相关
引入项目的文件 info.plist 添加内容 WXApi.registerApp(Config.wx.APP_ID,enableMTA: true)//注册微信api(在AppDelegate里面注 ...
- java排序之冒泡排序
代码: package com.cn.algorithm_arithmetic算法; /** * 本程序记录了经典排序算法之冒泡排序 * @author Administrator * */ publ ...
- Codeforces Round #546 (Div. 2) B. Nastya Is Playing Computer Games
链接:https://codeforces.com/contest/1136/problem/B 题意: 有n个井盖,每个井盖上有一个小石头. 给出n和k,k表示刚开始在第k个井盖上方. 有三种操作, ...
- 最长上升子序列LIS(云笔记图片版)
- SNMP消息传输机制
1.引言 基于TCP/IP的网络管理包含3个组成部分: 1) 一个管理信息库MIB(Management Information Base).管理信息库包含所有代理进程的所有可被查询和修改的参数.RF ...
- 120 Triangle 三角形最小路径和
给出一个三角形(数据数组),找出从上往下的最小路径和.每一步只能移动到下一行中的相邻结点上.比如,给你如下三角形:[ [2], [3,4], [6,5,7], [4,1,8,3]] ...
- python学习之串口编程
# coding=utf-8import serial ser=serial.Serial('com1',9600)ser.write(b"hello")while 1: ser. ...
- centos7安装iptables
使用CentOS 7时发现使用iptables防火墙时提示错误Unit iptables.service failed to load,意思是防火墙运行启动失败了,那么要如何处理呢. 一直用Cen ...
- phpdesigner 配置SVN