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. 【前端构建】WebPack实例与前端性能优化

    计划把微信的文章也搬一份上来. 这篇主要介绍一下我在玩Webpack过程中的心得.通过实例介绍WebPack的安装,插件使用及加载策略.感受构建工具给前端优化工作带来的便利. 壹 | Fisrt 曾几 ...

  2. android MVP设计模式!

    实现原理: MainActivity 用来更新UI,和显示业务逻辑的结果! LoginPresenterCompl 用来处理 业务逻辑 ILoginPresenter 业务处理类抽象出来的接口 ILo ...

  3. Java文件中出现这样的提示错误与解决方法:Cannot return from outside a function or method?

    1.打开  >>  Myeclipse或Eclipse.(我使用的是Myeclipse) 2.打开  >>  Window  >>  Preferences  如图 ...

  4. ASP.NET MVC 5 01 - ASP.NET概述

    本篇目录: ASP.NET 概述 .NET Framework 与 ASP.NET ASP.NET MVC简介 ASP.NET的特色和优势 典型案例 ▁▃▅ ASP.NET概述 ▅▃▁ 目前开发B/S ...

  5. Linux下安装 Posgresql 并设置基本参数

    在Linux下安装Postgresql有二进制格式安装和源码安装两种安装方式,这里用的是二进制格式安装.各个版本的Linux都内置了Postgresql,所以可直接通过命令行安装便可.本文用的是Cen ...

  6. 2-sql基本操作

    sql基本操作 一.Sqlplus常用命令 1.查看oracle数据库的进程 2.查看oracle数据库运行状态 3.显示实例名(数据库名) 4.用sys账户登陆到数据库 5.解锁账户scott,并登 ...

  7. Python 字符串相加问题

    今天在用Python拼接字符串时碰到个问题,从数据库取出来的数据以及获取到的时间等数据拼成了一个字符串a,将字符串a与自定义的字符串b拼接时一直中断,无法继续执行,也没有报错,将数据库取出数据变成自定 ...

  8. 基于H5的微信支付开发详解

    这次总结一下用户在微信内打开网页时,可以调用微信支付完成下单功能的模块开发,也就是在微信内的H5页面通过jsApi接口实现支付功能.当然了,微信官网上的微信支付开发文档也讲解的很详细,并且有实现代码可 ...

  9. Intellij IDEA 快捷键整理

    CSDN 2016博客之星评选结果公布      [系列直播]算法与游戏实战技术      "我的2016"主题征文活动 Intellij IDEA 快捷键整理(TonyCody) ...

  10. eclipse调试java程序的九个技巧

    转:http://www.cnblogs.com/lingiu/p/3802391.html 九个技巧: 逻辑结构 条件debug 异常断点 单步过滤 跳到帧 Inspect expressions ...