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. Oracle安装

    1.根据自己的操作系统,到Oracle官网下载相应的安装包 下载地址:http://download.oracle.com/otn/nt/oracle11g/112010/win32_11gR2_cl ...

  2. htm常用标签总结

    1.结构性定义 文件类型 <HTML></HTML> (放在档案的开头与结尾) 文件主题 <TITLE></TITLE> (必须放在「文头」区块内) 文 ...

  3. HTML中的标记-遁地龙卷风

    第三版 上一版本在未经验证的情况下,盲目的认为很多东西是那样,造成错误,非常抱歉. 0.什么是标记 <input type="checkbox" checked />& ...

  4. 教你怎么半天搞定Docker

    首先,不要把docker想的那么高大,它不就是先做个镜像,然后通过docker像虚拟机一样跑起来嘛...docker其实在真实业务场景中还是非常有局限性的.Dockerfile脚本也没那么好写,有些应 ...

  5. Node.js 教程 02 - 经典的Hello World

    前言: Node.js的介绍.安装及配置,上一节都已经介绍过了,如果有不清楚的也可以留言或者直接问度娘. 本节: 本节主要以一个简单的例子简单体验一下Node.js,用到了两种方法.下面会介绍. 总之 ...

  6. VS 母版使用配置技巧

    采用web.config配置母版,方便母版的变更,处理方法: 1.在web.config配置如下内容: <configuration> <system.web> <pag ...

  7. Windows下磁盘分配操作

    问题概述:在装系统的时候有时候并不能一下分出完全符合我们使用习惯的分区大小,我们可能需要在后期调整分区大小.以下是有关分区大小调整的操作. 使用工具:Windows磁盘管理工具. 操作步骤: 1.使用 ...

  8. 异步HTTPHandler的实现

    使用APM的方式实现 using System; using System.Web; using System.Threading; class HelloWorldAsyncHandler : IH ...

  9. 杂项之使用qq邮箱发送邮件

    杂项之使用qq邮箱发送邮件 本节内容 特殊设置 测试代码 1. 特殊设置 之前QQ邮箱直接可以通过smtp协议发送邮件,不需要进行一些特殊的设置,但是最近使用QQ邮箱测试的时候发现以前使用的办法无法奏 ...

  10. angular学习笔记(二十八-附1)-$resource中的资源的方法

    通过$resource获取到的资源,或者是通过$resource实例化的资源,资源本身就拥有了一些方法,$save,$delete,$remove,可以直接调用来保存该资源: 比如有一个$resour ...