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 Studio 编写 JNI

    之前一直都不知怎么编写JNI,今天刚好学习一下,感谢梦真的指教,以及提供的文档. 参考链接 http://blog.csdn.net/u011168565/article/details/518781 ...

  2. PHP常用技术文之文件操作和目录操作总结

    <?php header("content-type:text/html;charset=utf-8"); /* *声明一个函数,传入文件名获取文件属性 *@param st ...

  3. HTML邮件注意事项(转)

    1.全局规则之一,不要写<style>标签.不要写class,所有CSS都用style属性,什么元素需要什么样式就用style写内联的CSS. 2.全局规则之二,少用图片,邮箱不会过滤你的 ...

  4. SHGetSpecialFolderPath用法

    The SHGetSpecialFolderPath function retrieves the path of a special folder that is identified by its ...

  5. C++之函数模板

    C++之函数模板与模版函数 直接上代码:  C++ Code  12345678910111213141516171819202122232425262728293031323334353637383 ...

  6. easyui上传文件

    效果图: 代码: <form id="importFileForm" method="post" enctype="multipart/form ...

  7. 写一个SingleTon,(饿最终、懒同步)

    1.饿汉式: public class SingleTon { private SingleTon(){ } private final static SingleTon instance = new ...

  8. Oracle数据库列出所有表名SQL语句

    select table_name from user_tables

  9. python里的生成器

    author:headsen chen date:2018-03-22 10:59:46 notice:This article created by headsen chen himself and ...

  10. Android 通过findViewById方式创建TabHost

    package org.shuxiang.tabhostsample; import android.os.Bundle; import android.app.ActivityGroup; impo ...