atomic原子类实现机制_JUC学习笔记--Atomic原子类

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 ...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值