J.U.C 框架学习顺序 http://blog.csdn.net/chen7253886/article/details/52769111

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<Integer> asr= new AtomicStampedReference<Integer>(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<T> {
final T reference;
final int stamp;
private Pair(T reference, int stamp) {
this.reference = reference;
this.stamp = stamp;
}
static <T> Pair<T> of(T reference, int stamp) {
return new Pair<T>(reference, stamp);
}
}
//对比AtomicInteger value由int 改为Pair<V>
private volatile Pair<V> pair; public boolean compareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp) {
Pair<V> 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<V> cmp, Pair<V> val) {
return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
}

JUC学习笔记--Atomic原子类的更多相关文章

  1. JUC源码学习笔记4——原子类,CAS,Volatile内存屏障,缓存伪共享与UnSafe相关方法

    JUC源码学习笔记4--原子类,CAS,Volatile内存屏障,缓存伪共享与UnSafe相关方法 volatile的原理和内存屏障参考<Java并发编程的艺术> 原子类源码基于JDK8 ...

  2. JUC 中的 Atomic 原子类总结

    1 Atomic 原子类介绍 Atomic 翻译成中文是原子的意思.在化学上,我们知道原子是构成一般物质的最小单位,在化学反应中是不可分割的.在我们这里 Atomic 是指一个操作是不可中断的.即使是 ...

  3. Juc中Atomic原子类总结

    1 Atomic原子类介绍 2 基本类型原子类 3 数组类型原子类 4 引用类型原子类 5 对象的属性修改类型原子类

  4. JUC学习笔记——共享模型之管程

    JUC学习笔记--共享模型之管程 在本系列内容中我们会对JUC做一个系统的学习,本片将会介绍JUC的管程部分 我们会分为以下几部分进行介绍: 共享问题 共享问题解决方案 线程安全分析 Monitor ...

  5. JUC学习笔记(四)

    JUC学习笔记(一)https://www.cnblogs.com/lm66/p/15118407.html JUC学习笔记(二)https://www.cnblogs.com/lm66/p/1511 ...

  6. JUC学习笔记(二)

    JUC学习笔记(一)https://www.cnblogs.com/lm66/p/15118407.html 1.Lock接口 1.1.Synchronized 1.1.1.Synchronized关 ...

  7. JUC学习笔记——进程与线程

    JUC学习笔记--进程与线程 在本系列内容中我们会对JUC做一个系统的学习,本片将会介绍JUC的进程与线程部分 我们会分为以下几部分进行介绍: 进程与线程 并发与并行 同步与异步 线程详解 进程与线程 ...

  8. JUC学习笔记——共享模型之内存

    JUC学习笔记--共享模型之内存 在本系列内容中我们会对JUC做一个系统的学习,本片将会介绍JUC的内存部分 我们会分为以下几部分进行介绍: Java内存模型 可见性 模式之两阶段终止 模式之Balk ...

  9. Java CAS同步机制 原理详解(为什么并发环境下的COUNT自增操作不安全): Atomic原子类底层用的不是传统意义的锁机制,而是无锁化的CAS机制,通过CAS机制保证多线程修改一个数值的安全性。

    精彩理解:  https://www.jianshu.com/p/21be831e851e ;  https://blog.csdn.net/heyutao007/article/details/19 ...

随机推荐

  1. java script第一篇(按钮全选的实现)

    今天刚学了java script,记录下学习新知识的点滴.以下是操作步骤.鉴于我是初级者,如有错误,恳请读者指正.万分谢谢. 1.新建一个文档(用NotePad软件,为了使得在浏览器中打开不是乱码,在 ...

  2. Atitit 在线支付系统功能设计原理与解决方案 与目录

    Atitit 在线支付系统功能设计原理与解决方案 与目录 1.1. 支付系统1 1.2. 独立的支付子体系..微服务架构..1 1.3. 参考书籍1 支付战争 [The PayPal Wars:Bat ...

  3. EXD_BAD_ACCEEE

    iOS开发过程中,普通的bug通常较容易定位问题所在,但是,EXD_BAD_ACCEEE问题却比较不易查找问题.本文记录下解决EXD_BAD_ACCEEE问题的过程.首先说一下 EXC_BAD_ACC ...

  4. angularJS 学习演示

    开源网址(带中文说明注释):https://github.com/EnhWeb/angularJS.git

  5. Drop all the tables, stored procedures, triggers, constraints and all the dependencies in one SQL statement

    Is there any way in which I can clean a database in SQl Server 2005 by dropping all the tables and d ...

  6. Oracle数据行拆分多行

    工作和学习中常常会遇到一行要分割成多行数据的情况,在此整理一下做下对比. 单行拆分 如果表数据只有一行,则可以直接在原表上直接使用connect by+正则的方法,比如: select regexp_ ...

  7. CentOS中的环境变量配置文件

    CentOS的环境变量配置文件体系是一个层级体系,这与其他多用户应用系统配置文件是类似的,有全局的,有用户的,有shell的,另外不同层级有时类似继承关系.下面以PATH变量为例. 1.修改/etc/ ...

  8. Android使用最小宽度限定符时最小宽度的计算

    Android开发中最头疼的问题之一就是兼容不同尺寸和分辨率的设备.这里推荐一篇总结的比较完整的<Android开发:最全面.最易懂的Android屏幕适配解决方案>.这篇文章对屏幕兼容的 ...

  9. APUE学习之三个特殊位 设置用户ID(set-user-ID),设置组ID(set-group-ID),sticky

    设置用户ID(set-user-ID),设置组ID(set-group-ID),sticky   set-user-ID: SUID      当文件的该位有设置时,表示当该文件被执行时,程序具有文件 ...

  10. ubuntu下修改键位

    尴尬的背景: 服役5年的笔记本,最近键盘失灵,部分键位彻底失去响应.最蛋疼的是左右方向键都不能用了 ○| ̄|_ 解决方案是,通过xmodmap命令,用其他相对鸡肋些的键位替代方向键. 1 查看各个键位 ...