CAS
CAS(Compare-And-Swap,比较并交换)操作是CPU中术语,它保证了操作的原子性。CAS指令需要三个操作数,分别是:
V:内存位置(也就是本次操作变量的内存地址);
A:旧的预期值;
B: 操作完成后的新值。
CAS指令执行时,当且仅当V符合旧预期值A时,处理器用新值B更新V的值,否则它就不执行更新,无论是否更新,都会返回V的旧值,整个CAS操作是一个原子操作。在JDK1.5之后,Java程序中才可以使用CAS操作,该操作由sun.misc.Unsafe类里的compareAndSwapXXX()方法包装提供,虚拟机在内部对这些方法做了特殊处理。在JDK1.5中提供了原子变量,如AtomicInteger,AtomicLong等,由并发大师Doug
Lea操刀,提供了在单个变量上面不需要锁的线程安全性。现在就让我们走进AtomicInteger的世界中,探究它是如何实现的,并领略大师的风采。
AtomicInteger中原子操作的实现
通过这一小部分的分析,我们就弄明白了AtomicInteger中原子操作的实现,首先看看AtomicInteger中有哪些状态
public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L;
//使用Unsafe.compareAndSwapInt来执行修改操作,CAS是通过Unsafe.compareAndSwapXXX()方法实现的
private static final Unsafe unsafe = Unsafe.getUnsafe();
//value在内存中的地址偏移量
private static final long valueOffset;
static {
try {
//获得value的内存地址偏移量
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
//当前对象代表的值,注意是volatile
private volatile int value;
在这一段代码中,我们需要注意三个方面,也就是AtomicInteger的三个字段:
(1)unsafe字段,AtomicInteger包含了一个Unsafe类的实例,unsafe就是用来实现CAS的;
(2)value字段,表示当前对象代码的基本类型的值,AtomicInteger是int型的线程安全包装类,value就代码了AtomicInteger的值。注意,这个字段是volatile的。
(3)valueOfset,通过字面意思就可以看出来valueOfset是value在内存中的偏移量,也就是在内存中的地址,通过Unsafe.objectFieldOffset(Field f)获取。前面在讲CAS时,我们提到需要操作内存的位置,valueOfset就是这个位置。
AtomicInteger中的CAS
public final boolean compareAndSet(int expect,int update)就是CAS的具体实现,其他所有的原子操作都是依赖于此方法,前面已经提到了,Java中的CAS是通过Unsafe类实现的,这个方法就是通过调用Unsafe.compareAndSwapInt(this,valueOfset,expect,udate)方法来实现的,其中valueOffset就是要操作的内存地址,expect是旧值,update是新值,当且仅当valueOffset内存中的值等于expect时,才用update更新旧值。其代码如下:
/**
* 原子操作
* CAS:Compare-and-Swap
* 如果当前值==expect,则设置新值
*/
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
AtomicInteger提供了好几个原子操作变量的方法:
可以看到,每一种操作(自增,自减,加给定值)都提供了对称的操作,其中getAndXXX()方法是返回旧值,XXXAndGet()返回的是新值。这些操作的实现方式都是相同的,我们以getAndIncrement()为例,来讲解它是如何实现原子操作的。首先看getAndIncrement()的源码:
/**
* 原子操作,实现自增操作,通过CAS实现,返回自增之前的值
* 实现原理是这样的:
* 1.首先获得当前值,保存到current中,next=current + 1
* 2.如果CAS成功,则返回current
* 如果CAS不成功,这说明刚刚有其他的线程修改了当前值,current已经失效了,next也已经失效了
* 只能重新获取当值,并继续CAS,直到成功为止
*/
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}
在上面的注释中已经说的比较明白了,但我还是愿意再啰嗦两句:
(1)首先获得当前值,保存到current中,并把current的下一个值保存到next中,next=current+1
(2)调用compareAndSet(current,next)尝试自增,如果自增成功,则返回current;如果自增失败,则说明已经有其他线程修改value的值,current中的值和next中的值已经失效了,要重新获取当前值,重复刚才的CAS操作,直到成功位置。
可以看到,通过第(2)步的操作,确实实现了多线程下的安全,即使在自增的时候有其他线程修改了当前值,自增操作也不会覆盖已经修改的值,而是在当前最新值的基础上实现自增。演示一下不使用CAS的错误情况和这种实现方式的正确性
a.错误的自增,假设当前value=8,同时有两个线程t1,t2对value执行自增操作,执行顺序如下:
执行完成后,t2的值把t1的值给覆盖了,执行完成后,现在value=9,正确的结果应该是10。在下图中,通过CAS以同样的顺序执行,获得的结果就是正确的:
上面的分析基本上就概括了AtomicInteger实现的全部了。但是CAS并不是没有缺点,概括起来说,CAS就三个缺点:
(1)ABA问题,如果V的初始值是A,在准备赋值的时候检查到它仍然是A,那么能说它没有改变过吗?也许V经历了这样一个过程:它先变成了B,又变成了A,使用CAS检查时以为它没变,其实却变里;
(2)循环时间长,开销大,通过自旋CAS一直在消耗CPU
(3)只能保证一个共享变量的原子操作,当对多个共享变量操作时就无法保证原子性了。
AtomicInteger源码分析:
package com.java.source;
import sun.misc.Unsafe;
public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L;
//使用Unsafe.compareAndSwapInt来执行修改操作,CAS是通过Unsafe.compareAndSwapXXX()方法实现的
private static final Unsafe unsafe = Unsafe.getUnsafe();
//value在内存中的地址偏移量
private static final long valueOffset;
static {
try {
//获得value的内存地址偏移量
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
//当前对象代表的值,注意是volatile
private volatile int value;
/*使用给定的值创建对象,也就是把给定的值包装起来*/
public AtomicInteger(int initialValue) {
value = initialValue;
}
/*默认初始化为0*/
public AtomicInteger() {
}
/*getter/setter*/
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);
}
/*原子操作:设定新值,返回旧值,通过CAS完成*/
public final int getAndSet(int newValue) {
for (;;) {
int current = get();
if (compareAndSet(current, newValue))
return current;
}
}
/**
* 原子操作
* CAS:Compare-and-Swap
* 如果当前值==expect,则设置新值
*/
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
/**
* 原子操作,功能与compareAndSet一样
* 有可能意外失败,且不保证排序,但是调用的代码是完全一样的,JVM又在内部做了手脚?
* 在极少情况下用来替代compareAndSet
*/
public final boolean weakCompareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
/**
* 原子操作,实现自增操作,通过CAS实现,返回自增之前的值
* 实现原理是这样的:
* 1.首先获得当前值,保存到current中,next=current + 1
* 2.如果CAS成功,则返回current
* 如果CAS不成功,这说明刚刚有其他的线程修改了当前值,current已经失效了,next也已经失效了
* 只能重新获取当值,并继续CAS,直到成功为止
*/
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}
/**
* 原子操作,实现自减,通过CAS实现,返回当前值
* 实现方法同getAndIncrement()相同
*/
public final int getAndDecrement() {
for (;;) {
int current = get();
int next = current - 1;
if (compareAndSet(current, next))
return current;
}
}
/**
* 原子操作,将当前值增加delta,并返回当前值
* 实现原理同getAndIncrement()相同,只不过一个是增1,一个是增delta
*/
public final int getAndAdd(int delta) {
for (;;) {
int current = get();
int next = current + delta;
if (compareAndSet(current, next))
return current;
}
}
/*原子操作,自增一,并返回增加后的值*/
public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
/*原子操作,自减,并返回减小后的值*/
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;
}
}
/**
* 一些常规方法
*/
public String toString() {
return Integer.toString(get());AtomicLong
}
public int intValue() {
return get();
}
public long longValue() {
return (long)get();
}
public float floatValue() {
return (float)get();
}
public double doubleValue() {
return (double)get();
}
}
转载请注明出处:喻红叶《Java并发-AtomicInteger源码分析》
分享到:
相关推荐
Java并发之AtomicInteger源码分析 AtomicInteger是Java并发包下面提供的原子类,主要操作的是int类型的整型,通过调用底层Unsafe的CAS等方法实现原子操作。下面是对AtomicInteger的源码分析。 1. 什么是原子操作...
《Java并发编程源码》是深入理解Java多线程编程技术的重要参考资料,它包含了实际案例和源代码,有助于...源码学习是提高编程技能的有效途径,特别是对于复杂的并发场景,源码分析能帮助我们更好地理解和解决问题。
《JUC并发编程与源码分析视频课》是一门深入探讨Java并发编程的课程,主要聚焦于Java Util Concurrency(JUC)库的使用和源码解析。JUC是Java平台提供的一组高级并发工具包,它极大地简化了多线程编程,并提供了更...
《Java并发编程的艺术》这本书是Java开发者深入理解并发编程的重要参考书籍。这本书全面地介绍了Java平台上的并发和多线程编程技术,旨在帮助开发者解决在实际工作中遇到的并发问题,提高程序的性能和可伸缩性。 ...
总的来说,这个资源包涵盖了Java并发编程的核心概念和技术,结合源码分析,学习者可以深入理解并发编程的原理,提升在实际项目中的应用能力。通过实践和调试源码,可以更好地掌握这些知识点,提高解决问题的能力。
源码分析: 1. **线程与多线程**:Java中的线程是并发编程的基础,通过`Thread`类或实现`Runnable`接口可以创建线程。源码中可能包含各种线程的创建和管理方式,如`start()`方法启动线程,`join()`等待线程结束,...
在这个压缩包中,包含了源码和PDF版的书籍内容,是学习和研究Java并发编程的重要资源。 并发编程是现代计算机系统中不可或缺的一部分,特别是在Java这种广泛用于企业级应用的平台上。Java提供了强大的并发工具和API...
通过对《Java并发编程艺术》源码的深入学习,你可以掌握上述知识点,并能够运用到实际项目中,编写出更加稳定和高效的并发程序。书中的例子和源码将有助于你理解和实践这些理论,从而提升你的并发编程能力。
Java并发编程是Java开发中的重要领域,特别是在多核处理器和分布式系统中,高效地利用并发可以极大地提升程序的性能和响应速度。`Java-concurrency-master.zip`这个压缩包很可能包含了关于Java并发编程的各种资料和...
《Java并发编程高阶技术-高性能并发框架源码解析与实战》是一本深入探讨Java并发编程的书籍,旨在帮助读者掌握高性能并发框架的核心原理,并通过源码解析与实战演练提升技术水平。在Java的世界里,并发编程是提升...
在Java编程领域,并发编程是不可或缺的一部分,尤其是在大型系统或高并发应用中。...同时,通过阅读和分析相关源码,如`java.util.concurrent`包下的类,可以更深入地理解其工作原理,提升解决问题的能力。
6. **源码分析(src)** - **源码结构**:书中示例的代码结构,包括类的设计、方法的实现,以及如何利用Java并发工具解决问题。 - **并发测试**:通过Junit或其他测试框架对并发代码进行测试,确保其正确性和性能...
《Java并发编程的艺术》是一本深入探讨Java多线程与并发编程的经典著作,它涵盖了Java并发编程中的核心概念和技术。...同时,源码分析也能帮助开发者更好地理解并发问题的产生和解决策略,提升在实际项目中的应用水平。
1. **线程池(ExecutorService)**:Java并发包通过`ExecutorService`接口和`ThreadPoolExecutor`类实现了线程池的概念。线程池可以有效地管理线程的创建和销毁,避免频繁创建销毁线程带来的性能开销。通过`...
《Java并发编程艺术》是一本深入探讨Java多线程与并发编程的经典著作,它涵盖了...通过深入学习和实践《Java并发编程艺术》的源码,开发者可以更好地理解和应用Java并发编程技术,提高多线程环境下的程序性能和稳定性。
通过查看`java.lang.Thread`、`java.util.concurrent`等类的源码,可以深入理解Java并发库的设计原理。同时,利用IDE的调试工具和性能分析工具(如VisualVM),可以帮助我们定位并发问题,优化代码性能。 在实际...
《Java并发编程 设计原则与模式 第二版》是一本深受程序员喜爱的经典书籍,由Addison Wesley出版。这本书深入探讨了Java平台上的多线程编程技术,为开发者提供了丰富的设计原则和模式,帮助他们理解和解决并发环境中...
本书涵盖了从基本概念到高级特性的全方位知识,是提升Java并发编程能力的不二之选。 在Java中,多线程是并发编程的基础,它允许程序同时执行多个任务,从而提高系统的利用率和性能。Java 7在并发方面引入了许多改进...
《JAVA并发编程实践》是一本深入探讨Java并发编程的权威指南。这本书主要涵盖了Java平台上的多线程和并发设计模式,旨在帮助开发者理解和掌握在Java环境中进行高效并发编程的关键技术。书中不仅提供了丰富的理论知识...