java.util.concurrent.atomic包中对基本类型进行原子操作的类有:AtomicInteger、AtomicBoolean、AtomicLong。

下面通过一个测试程序来验证一下AtomicInteger真的实现了原子操作

public class AtomicIntegerTest {
public static AtomicInteger count=new AtomicInteger(0);
public static void main(String[] args) throws IOException {
/*一个线程递增10000次*/
new Thread() {
public void run() {
for (int i = 0; i < 10000; i++) { System.out.println(this.getName() + ">>" + count.addAndGet(1));
}
} }.start();
/*
* 两个线程分别递减5000次
*/
new Thread() {
public void run() {
for (int i = 0; i < 5000; i++) { System.out.println(this.getName() + ">>" + count.addAndGet(-1));
}
} }.start(); new Thread() {
public void run() {
for (int i = 0; i < 5000; i++) { System.out.println(this.getName() + ">>" + count.addAndGet(-1));
}
} }.start();
System.in.read();
System.out.println("最终结果:"+count);
}
}

按照我们的预期如果最终结果是0,那么就可以说明确实实现了原子操作。

通过查看源码发现update操作最终都是通过调用compareAndSet方法,也就是通过Unsafe调用C程序执行CPU命令。

/**
* Atomically sets to the given value and returns the old value.
*
* @param newValue the new value
* @return the previous value
*/
public final int getAndSet(int newValue) {
for (;;) {
int current = get();
if (compareAndSet(current, newValue))
return current;
}
}
/**
* Atomically increments by one the current value.
*
* @return the previous value
*/
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}

public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

另外,这种自旋的方式保证操作成功的方式在竞争激烈的情况对CPU资源消耗比较大。

因为基本类型的原子类都比较近简单,实现方式也比较接近,在这就不细说了。

AtomicBoolean 最终也是调用了unsafe.compareAndSwapInt方法,

AtomicLong最终调用了unsafe.compareAndSwapLong方法,AtomicLong会多一个判断虚拟机是否支持long型无锁CompareAndSet,不过好像也没用它做任何事,意义何在呢???

 /**
* Records whether the underlying JVM supports lockless
* compareAndSwap for longs. While the Unsafe.compareAndSwapLong
* method works in either case, some constructions should be
* handled at Java level to avoid locking user-visible locks.
*/
static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8(); /**
* Returns whether underlying JVM supports lockless CompareAndSet
* for longs. Called only once and cached in VM_SUPPORTS_LONG_CAS.
*/
private static native boolean VMSupportsCS8();

延伸知识点

public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L; // setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();//Unsafe仅供JDK内部调用,我们写的程序不能直接调用
private static final long valueOffset;//value相对对象地址的偏移量
   static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
} private volatile int value;//用volatile修饰,value值被某个线程修改后其他线程可以读到最新值

AtomicInteger有个属性valueOffset,并且通过静态代码块来初始化。valueOffet就是属性value相对AtomicInteger对象起始地址的偏移量,比如AtomicInteger对象实例化以后地址是1,valueOffet=N,那么value属性的起始地址就是1+N,做compareAndSwap的时候就可以直接定位到value的地址。

具体原理还要从Java对象内存布局说起:

在HotSpot虚拟机中,对象的内存布局可以分为三部分:对象头(Header)、 实例数据(Instance Data)和对齐填充(Padding)。

  • 对象头
    • 存储对象自身的运行时数据:Mark Word(在32bit和64bit虚拟机上长度分别为32bit和64bit),包含如下信息:

      • 对象hashCode
      • 对象GC分代年龄
      • 锁状态标志(轻量级锁、重量级锁)
      • 线程持有的锁(轻量级锁、重量级锁)
      • 偏向锁相关:偏向锁、自旋锁、轻量级锁以及其他的一些锁优化策略是JDK1.6加入的
    • 类型指针:对象指向类元数据的指针(32bit-->32bit,64bit-->64bit(未开启压缩指针),32bit(开启压缩指针))
      • JVM通过这个指针来确定这个对象是哪个类的实例(根据对象确定其Class的指针)

  • 实例数据:对象真正存储的有效信息  

  • 对齐填充

    • JVM要求对象的大小必须是8的整数倍,若不是,需要补位对齐

J.U.C Atomic(二)基本类型原子操作的更多相关文章

  1. J.U.C atomic 数组,字段原子操作

    这里看一下原子数组操作和一些其他的原子操作. AtomicIntegerArray/AtomicLongArray/AtomicReferenceArray的API类似,选择代表性的AtomicInt ...

  2. 24.Java中atomic包中的原子操作类总结

    1. 原子操作类介绍 在并发编程中很容易出现并发安全的问题,有一个很简单的例子就是多线程更新变量i=1,比如多个线程执行i++操作,就有可能获取不到正确的值,而这个问题,最常用的方法是通过Synchr ...

  3. 从头开始学JavaScript (十二)——Array类型

    原文:从头开始学JavaScript (十二)--Array类型 一.数组的创建 注:ECMAscript数组的每一项都可以保存任何类型的数据 1.1Array构造函数 var colors = ne ...

  4. java 基础知识二 基本类型与运算符

    java  基础知识二 基本类型与运算符 1.标识符 定义:为类.方法.变量起的名称 由大小写字母.数字.下划线(_)和美元符号($)组成,同时不能以数字开头 2.关键字 java语言保留特殊含义或者 ...

  5. { MySQL基础数据类型}一 介绍 二 数值类型 三 日期类型 四 字符串类型 五 枚举类型与集合类型

    MySQL基础数据类型 阅读目录 一 介绍 二 数值类型 三 日期类型 四 字符串类型 五 枚举类型与集合类型 一 介绍 存储引擎决定了表的类型,而表内存放的数据也要有不同的类型,每种数据类型都有自己 ...

  6. NET设计规范二:类型成员设计

    http://www.cnblogs.com/yangcaogui/archive/2012/04/20/2459567.html 接着 → .NET设计规范一:设计规范基础 上一篇,我们来了解下类型 ...

  7. 010 01 Android 零基础入门 01 Java基础语法 02 Java常量与变量 04 变量的三个元素的详细介绍之二——变量类型——即Java中的数据类型

    010 01 Android 零基础入门 01 Java基础语法 02 Java常量与变量 04 变量的三个元素的详细介绍之二--变量类型--即Java中的数据类型 Java中变量的三要素 变量名 变 ...

  8. 多线程爬坑之路-J.U.C.atomic包下的AtomicInteger,AtomicLong等类的源码解析

    Atomic原子类:为基本类型的封装类Boolean,Integer,Long,对象引用等提供原子操作. 一.Atomic包下的所有类如下表: 类摘要 AtomicBoolean 可以用原子方式更新的 ...

  9. [Java多线程]-J.U.C.atomic包下的AtomicInteger,AtomicLong等类的源码解析

    Atomic原子类:为基本类型的封装类Boolean,Integer,Long,对象引用等提供原子操作. 一.Atomic包下的所有类如下表: 类摘要 AtomicBoolean 可以用原子方式更新的 ...

随机推荐

  1. 史上最严管控,Android P非SDK接口管控特性解读及适配

    导读 在 Android P 版本中,谷歌加入了非 SDK 接口使用限制,无论是通过调用.反射还是JNI等方式,开发者都无法对非 SDK 接口进行访问,此接口的滥用将会带来严重的系统兼容性问题. 针对 ...

  2. Linux快速定位并且杀掉占用端口的进程

    1.定位 lsof -i:8811(端口号) 2.杀掉进程 kill -9 63924

  3. Hadoop源码分析之Configuration

    转自:http://www.it165.net/admin/html/201312/2178.html org.apache.hadoop.conf.Configuration类是Hadoop所有功能 ...

  4. Spring Framework 官方文档学习(二)之IoC容器与bean lifecycle

    到目前为止,已经看了一百页.再次感慨下,如果想使用Spring,那可以看视频或者找例子,但如果想深入理解Spring,最好还是看官方文档. 原计划是把一些基本接口的功能.层次以及彼此的关系罗列一下.同 ...

  5. WinDbg 解决Font.ToLogFont AccessViolationExcetion

    有个程序总是在windows 2003 server 异常退出. 并且,  查看调用栈也肯奇怪, 应该是很正常的调用. 怀疑是堆溢出. 开启heap trace : C:\Program Files\ ...

  6. bootstrap基础学习八篇

    bootstrap辅助类 a.对于文本颜色 以下不同的类展示了不同的文本颜色.如果文本是个链接鼠标移动到文本上会变暗: 类 描述 .text-muted "text-muted" ...

  7. 求出每个team粉丝数最多的3个国家

    有这么个表 fans(team,nationality,fanCount) 'Barcelona','Germany',12000'Barcelona','Spain',18000'Barcelona ...

  8. WPF 纯代码生成界面(不使用XAML)

    对于编写 WPF 应用程序,只是用代码进行开发而不使用任何 XAML 不是常见的方式(但是仍然完全支持).只使用代码进行开发的明显缺点是,有可能会使用编写 WPF 应用程序成为极端乏味的工作. WPF ...

  9. XDocument简单入门

    [+]   1.什么是XML? 2.XDocument和XmlDocument的区别? 3.XDocument 4.XmlDocument 5.LINQ to XML 6.XML序列化与反序列化 因为 ...

  10. java 实现对指定目录的文件进行下载

    @RequestMapping("/exportDocument") @ResponseBody public void exportDocument(HttpServletReq ...