J.U.C Atomic(二)基本类型原子操作
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(二)基本类型原子操作的更多相关文章
- J.U.C atomic 数组,字段原子操作
这里看一下原子数组操作和一些其他的原子操作. AtomicIntegerArray/AtomicLongArray/AtomicReferenceArray的API类似,选择代表性的AtomicInt ...
- 24.Java中atomic包中的原子操作类总结
1. 原子操作类介绍 在并发编程中很容易出现并发安全的问题,有一个很简单的例子就是多线程更新变量i=1,比如多个线程执行i++操作,就有可能获取不到正确的值,而这个问题,最常用的方法是通过Synchr ...
- 从头开始学JavaScript (十二)——Array类型
原文:从头开始学JavaScript (十二)--Array类型 一.数组的创建 注:ECMAscript数组的每一项都可以保存任何类型的数据 1.1Array构造函数 var colors = ne ...
- java 基础知识二 基本类型与运算符
java 基础知识二 基本类型与运算符 1.标识符 定义:为类.方法.变量起的名称 由大小写字母.数字.下划线(_)和美元符号($)组成,同时不能以数字开头 2.关键字 java语言保留特殊含义或者 ...
- { MySQL基础数据类型}一 介绍 二 数值类型 三 日期类型 四 字符串类型 五 枚举类型与集合类型
MySQL基础数据类型 阅读目录 一 介绍 二 数值类型 三 日期类型 四 字符串类型 五 枚举类型与集合类型 一 介绍 存储引擎决定了表的类型,而表内存放的数据也要有不同的类型,每种数据类型都有自己 ...
- NET设计规范二:类型成员设计
http://www.cnblogs.com/yangcaogui/archive/2012/04/20/2459567.html 接着 → .NET设计规范一:设计规范基础 上一篇,我们来了解下类型 ...
- 010 01 Android 零基础入门 01 Java基础语法 02 Java常量与变量 04 变量的三个元素的详细介绍之二——变量类型——即Java中的数据类型
010 01 Android 零基础入门 01 Java基础语法 02 Java常量与变量 04 变量的三个元素的详细介绍之二--变量类型--即Java中的数据类型 Java中变量的三要素 变量名 变 ...
- 多线程爬坑之路-J.U.C.atomic包下的AtomicInteger,AtomicLong等类的源码解析
Atomic原子类:为基本类型的封装类Boolean,Integer,Long,对象引用等提供原子操作. 一.Atomic包下的所有类如下表: 类摘要 AtomicBoolean 可以用原子方式更新的 ...
- [Java多线程]-J.U.C.atomic包下的AtomicInteger,AtomicLong等类的源码解析
Atomic原子类:为基本类型的封装类Boolean,Integer,Long,对象引用等提供原子操作. 一.Atomic包下的所有类如下表: 类摘要 AtomicBoolean 可以用原子方式更新的 ...
随机推荐
- /proc/meminfo分析
参考: 1. linux/Documentation/filesystems/proc.txt 2. Linux 中 /proc/meminfo 的含义 3. redhat deployment gu ...
- mnesia怎样改动表结构
mnesia创建的时候须要指定表record结构,假设定义的record结构改动了,就要更新数据的表结构.否则mnesia无法正常读取和写入数据. 我们最開始是这样定义结构的 -record(pers ...
- ASP.NET MVC4 异常拦截
ASP.NET MVC4 程序发生异常时,通过拦截Action的异常,重写ActionFilterAttribute 的方法OnActionExecuted实现. 具体实现代码如下: /// < ...
- C++ 匿名对象产生场景
//匿名对象产生的三种场景 #include<iostream> using namespace std; class Point{ public: Point(int a,int b){ ...
- 关于Cocos2d-x中两个场景之间参数的传递
两个场景之间,有的时候要进行参数传递,如果想通过实例化出一个场景,从而得到属性和方法是不对的想法 你有两个场景,第一场景是用户登录界面,第二场景则是你登录后的界面,你如何将用户登录的值传到第二个场景呢 ...
- NANDflash和NORflash的区别(设计师在使用闪存时需要慎重选择)
NANDflash和NORflash的区别(设计师在使用闪存时需要慎重选择) NOR和NAND是现在市场上两种主要的非易失闪存技术.Intel于1988年首先开发出NOR flash技术,彻底 ...
- c# word excel 二进制 存入数据库
在Sql Server中存储.读写Word文件,需要将指定表字段添加为Image类型,示例表结构为:1 CREATE TABLE CONTRACTS ( 2 ID VARCHAR (50), 3 CO ...
- 编程之美 set 13 光影切割问题
题目 给出几条线段, 求解这几条线段把给定平面切成的份数 思路 1. 枚举 3 条直线的情况, 发现有规律可循 两条直线, 一个交点 -> 空间分成 4 份 三条直线, 两个交点 -> 空 ...
- MVC框架图
http://www.cnblogs.com/zgynhqf/archive/2010/11/19/1881449.html MVC框架图 http://www.cnblogs.com/zhang ...
- iOS开发之 -- bundle程序束的制造
我们在写项目的时候,需要添加大量的图片,这个时候除了在x-code-->Assets文件里面添加图片外,还可以添加程序束,这样的话 项目看起来比较整齐,也显得比较专业,下面就来说一下程序束的制造 ...