Atomic 原子操作类包
Atomic包 主要是在多线程环境下,无锁的进行原子操作。核心操作是基于UnSafe类实现的CAS方法
CAS
CAS: compareAndSwap :传入两个值:期望值和新值,判断原有值与期望值相等,则给其赋新值,否则不做任何操作。
CAS硬件支持
现代的CPU提供了特殊的指令,可以自动更新共享数据,而且能够检测到其他线程的干扰。
Atomic源码
以AtomicInteger为例(AtomicBoolean也是把boolen转为int)
public class AtomicInteger extends Number implements java.io.Serializable {
//序列化相关
private static final long serialVersionUID = 6214790243416807050L;
//Unsafe类
private static final Unsafe unsafe = Unsafe.getUnsafe();
//内存地址偏移量
private static final long valueOffset;
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
//value值,因为无锁使用volatile保证线程加载到最新的值
private volatile int value;
//初始化
public AtomicInteger(int initialValue) {
value = initialValue;
}
public AtomicInteger() {
}
//获取当前值
public final int get() {
return value;
}
//赋值
public final void set(int newValue) {
value = newValue;
}
//延迟赋值,不保证新的赋值能立即被其他线程获取到
public final void lazySet(int newValue) {
unsafe.putOrderedInt(this, valueOffset, newValue);
}
//返回旧值并赋新值
public final int getAndSet(int newValue) {
for (;;) {// 等同于while(true)
int current = get();//获取旧值
if (compareAndSet(current, newValue))//以CAS方式赋值,直到成功返回
return current;
}
}
//对比期望值与value,不同返回false。相同将update赋给value 返回true
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
//与compareAndSet实现相同(可能为了以后更改)
public final boolean weakCompareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
//自增 i++
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}
//自减 i--
public final int getAndDecrement() {
for (;;) {
int current = get();
int next = current - 1;
if (compareAndSet(current, next))
return current;
}
}
//自定义增量数
public final int getAndAdd(int delta) {
for (;;) {
int current = get();
int next = current + delta;
if (compareAndSet(current, next))
return current;
}
}
//++i 返回自增后的值
public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
//--i 返回减少后的值
public final int decrementAndGet() {
for (;;) {
int current = get();
int next = current - 1;
if (compareAndSet(current, next))
return next;
}
}
//返回加上delta后的值
public final int addAndGet(int delta) {
for (;;) {
int current = get();
int next = current + delta;
if (compareAndSet(current, next))
return next;
}
}
/**
* Returns the String representation of the current value.
* @return the String representation of the current value.
*/
public String toString() {
return Integer.toString(get());
}
public int intValue() {
return get();
}
public long longValue() {
return (long)get();
}
public float floatValue() {
return (float)get();
}
public double doubleValue() {
return (double)get();
}
}
CAS的ABA问题
ABA问题:有两个线程,x线程读取值为A ,y线程读取值为A 并赋值为B,B线程再修改会A,此时x线程以A为旧值并赋新值仍然是成功的,
因为线程x不知道变量值经过A->B->A的修改。
AtomicStampedReference 解决ABA问题
先看看如何使用:
AtomicStampedReference asr= new AtomicStampedReference(1,0);
int stamp= asr.getStamp();
System.out.println(asr.compareAndSet(1,2,stamp,stamp+1));//true
System.out.println(asr.compareAndSet(2,1,stamp,stamp+1));//false
System.out.println(asr.compareAndSet(1,1,stamp+1,stamp+2));//false
System.out.println(asr.getReference());//2
对比AtomicInteger,可见AtomicStampedReference的构造函数多了一个参数、compareAndSet方法多了两个参数,看一下源码:
//对比AtomicInteger构造函数多了stamp参数
public AtomicStampedReference(V initialRef, int initialStamp) {
pair = Pair.of(initialRef, initialStamp);
}
private static class Pair {
final T reference;
final int stamp;
private Pair(T reference, int stamp) {
this.reference = reference;
this.stamp = stamp;
}
static Pair of(T reference, int stamp) {
return new Pair(reference, stamp);
}
}
//对比AtomicInteger value由int 改为Pair
private volatile Pair pair;
public boolean compareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp) {
Pair current = pair;
return
expectedReference == current.reference && //判断期望值与旧值是否相同
expectedStamp == current.stamp && //判断期望版本戳与旧版本戳是否相同
((newReference == current.reference &&
newStamp == current.stamp) || //如果值和戳没变化不执行下一行cas赋值代码
casPair(current, Pair.of(newReference, newStamp)));//cas赋值代码
}
//还是调用unsafe类
private boolean casPair(Pair cmp, Pair val) {
return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
}
JUC 中的 Atomic 原子类总结
1 Atomic 原子类介绍 Atomic 翻译成中文是原子的意思.在化学上,我们知道原子是构成一般物质的最小单位,在化学反应中是不可分割的.在我们这里 Atomic 是指一个操作是不可中断的.即使是 ...
Juc中Atomic原子类总结
1 Atomic原子类介绍 2 基本类型原子类 3 数组类型原子类 4 引用类型原子类 5 对象的属性修改类型原子类
(转)Java atomic原子类的使用方法和原理(一)
在讲atomic原子类之前先看一个小例子: public class UseAtomic { public static void main(String[] args) { AtomicIntege ...
Atomic原子类
Atomic原子类 Atomic原子类位于并发包java.util.concurrent下的java.util.concurrent.Atomic中. 1. 原子更新基本类型类 使用原子方式更新基本数 ...
多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类)
前言:刚学习了一段机器学习,最近需要重构一个java项目,又赶过来看java.大多是线程代码,没办法,那时候总觉得多线程是个很难的部分很少用到,所以一直没下决定去啃,那些年留下的坑,总是得自己跳进去填 ...
[Java多线程]-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类)
前言:刚学习了一段机器学习,最近需要重构一个java项目,又赶过来看java.大多是线程代码,没办法,那时候总觉得多线程是个很难的部分很少用到,所以一直没下决定去啃,那些年留下的坑,总是得自己跳进去填 ...
J.U.C 系列之Atomic原子类
一 什么是原子类? 所谓原子类必然是具有原子性的类,原子性操作--原子操作,百度百科中给的定义如下 "原子操作(atomic operation)是不需要synchronized" ...
Spring.NET学习笔记——目录(原)
目录 前言 Spring.NET学习笔记——前言 第一阶段:控制反转与依赖注入IoC&DI Spring.NET学习笔记1——控制反转(基础篇) Level 200 Spring.NET学习笔 ...
随机推荐
[汇编与C语言关系]4. 结构体和联合体
用反汇编的方法研究一下C语言的结构体: #include int main(int argc, char ** argv) { struct { char a; sho ...
AndroidStudio学习笔记-第一个安卓程序
要带一个本科生做一部分跟安卓有点关系的项目,于是趁着机会学习一下编写安卓程序. 第一篇材料来自谷歌官方,传送门:https://developer.android.com/training/basic ...
windows 10
http://auPL.v4.b1.download.windowsupdate.com/c/updt/2015/07/10240.16384.150709-1700.th1_clientchina_ ...
Android蓝牙连接以及数据接收发送
1.加入权限
CSS 高级技巧汇总
在我们平时写代码的时候没有没有掌握一些CSS技巧呢? 今天给大家分享一个.大家务必掌握这些小技巧,会让你非常高效率的写出网页的. ◆使用 :not ...
微信小程序简单入门1
参考文档:https://mp.weixin.qq.com/debug/wxadoc/dev/index.html 1 创建项目 开发者工具安装完成后,打开并使用微信扫码登录.选择创建"项 ...
遇到的问题&;思考
MYSQL需要批量修改表前缀: http://jingyan.baidu.com/article/11c17a2c742561f446e39d2f.html Select CONCAT( 'ALTER ...
PhysicalDrive
由于"\"是C/C+中转义符, "\\\\.\\"就相当于\\.\ 在Windows中 \\.\ 前缀用于标识设备,其中的"."表示本地计算 ...
Delphi字符串、PChar与字符数组之间的转换
来自:http://my.oschina.net/kavensu/blog/193719 ------------------------------------------------------- ...
java 中的valueOf方法和强转
case1:Object 对象转String 需要强调的是String.valueOf()方法,当参数为类型是object,且值时null的时候他的处理方式 public static String ...