很多情况下我们只是需要简单的,高效,线程安全的递增递减方法。注意,这里有三个条件:简单,意味着程序员尽可能少的底层或者实现起来比较简单;高效,意味着耗用资源要少,程序处理速度要快; 线程安全也非常重要,这个在多线程下能保证数据的正确性。这三个条件看起来比较简单,但是实现起来却难以令人满意。

通常情况下,在Java里面, ++i或者-- i不是线程安全的,这里面有三个独立的操作:读取变量当前值,为该值+1 /-1,然后写会新的值。在没有额外资源可以利用的情况下,只能使用加锁才能保证读-改-写这三个操作证的‘"原子性"。

在J.U.C(Doug Lea)为加入jdk之前,是采用纯Java实现的,于是不可避免的采用了synchronized关键字。

public final synchronized void set(int newValue);

public final synchronized int getAndSet(int newValue);

public final synchronized int incrementAndGet();

同时在变量上使用了volatile(后面详述)来保证get()的时候不用加锁。尽管synchronized的代价还是很高,但是在没有JNI的手段下纯Java语言还是不能实现此操作的。

来看看java.util.cocurrent.atomic.AtomicInteger开始:

int addAndGet(int delta);
//以原子方式将给定值与当前值想家。实际上就是等于线程安全版本的 i += delta boolean compareAndSet(int expect, int update);
//如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。如果
//更新成功就返回true, 否则就返回false, 并且不修改原值 int decrementAndGet();
//以原子方式将当前值减1,相当于线程安全版本的--i操作。 int get(); //获得当前值。 int getAndAdd(int delta);
//以原子方式将给定值与当前值相加,相当于线程版本的 t = i; i += //delat; return t; int getAndDecrement();
//以原子方式将当前值减1,相当于线程安全版本的i--; int getAndIncrement();
//以原子方式将当前值加1,相当于线程安全版本的i++; int getAndSet();
//以原子方式设定给定值,并返回旧值; int incrementAndGet();
//以原子方式将当前值加1,相当于线程安全版本的++i;

看几个实现:

  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); }
} private volatile int value;

调用sun.misc.Unsafe类实现cas操作(历史版权原因,Unsafe源码看不了),获取该对象value成员的内存地址;

  public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update); //根据unsafe的cas操作,返回true or false
}

看一下上面API的实现:

public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
} 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;
}
} public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}

方法实现总体差不多,for(;;)死循环,读取当前值,根据相应的加减cas操作,成功从for中返回,失败不同重试;

测试用例如下:

import java.util.concurrent.atomic.AtomicInteger;

import org.junit.Test;

import static org.junit.Assert.*;
public class AtomicIntegerTest { @Test
public void testAll() throws InterruptedException {
final AtomicInteger value = new AtomicInteger(10);
assertEquals(value.compareAndSet(1, 2), false);
assertEquals(value.get(), 10);
assertTrue(value.compareAndSet(10, 3));
assertEquals(value.get(), 3);
value.set(0); //
assertEquals(value.incrementAndGet(), 1);
assertEquals(value.getAndAdd(2), 1);
assertEquals(value.getAndSet(5), 3);
assertEquals(value.get(), 5); // final
final int threadSize = 5;
Thread[] threads = new Thread[threadSize];
for (int i = 0; i < threadSize; i++) {
threads[i] = new Thread() {
public void run() {
value.incrementAndGet();
}
};
}
for (Thread t : threads) {
t.start();
} for (Thread t : threads) {
t.join();
}
//
assertEquals(value.get(), 5 + threadSize);
}
}

原文来至:http://www.blogjava.net/xylz/archive/2010/07/08/325587.html

J.U.C atomic AtomicInteger解析的更多相关文章

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

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

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

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

  3. J.U.C Atomic(二)基本类型原子操作

    java.util.concurrent.atomic包中对基本类型进行原子操作的类有:AtomicInteger.AtomicBoolean.AtomicLong. 下面通过一个测试程序来验证一下A ...

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

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

  5. J.U.C Atomic(一)CAS原理

    CAS概念 CAS:Compare And Swap,比较并交换.java.util.concurrent包完全是建立于CAS机制之上的. CAS原理 Java CAS是通过调用Unsafe的nati ...

  6. AtomicInteger源码解析

    此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 1.原子类 可以实现一些原子操作 基于CAS 下面就以AtomicInteger为例. 2.AtomicIn ...

  7. 第十一章 AtomicInteger源码解析

    1.原子类 可以实现一些原子操作 基于CAS 下面就以AtomicInteger为例. 2.AtomicInteger 在没有AtomicInteger之前,对于一个Integer的线程安全操作,是需 ...

  8. Java:多线程,java.util.concurrent.atomic包之AtomicInteger/AtomicLong用法

    1. 背景 java.util.concurrent.atomic这个包是非常实用,解决了我们以前自己写一个同步方法来实现类似于自增长字段的问题. 在Java语言中,增量操作符(++)不是原子的,也就 ...

  9. J.U.C并发框架源码阅读(一)AtomicInteger

    基于版本jdk1.7.0_80 java.util.concurrent.atomic.AtomicInteger 代码如下 /* * ORACLE PROPRIETARY/CONFIDENTIAL. ...

随机推荐

  1. python科学计算_scipy_常数与优化

    scipy在numpy的基础上提供了众多的数学.科学以及工程计算中常用的模块:是强大的数值计算库: 1. 常数和特殊函数 scipy的constants模块包含了众多的物理常数: import sci ...

  2. 【JDK1.8】JDK1.8集合源码阅读——LinkedList

    一.前言 这次我们来看一下常见的List中的第二个--LinkedList,在前面分析ArrayList的时候,我们提到,LinkedList是链表的结构,其实它跟我们在分析map的时候讲到的Link ...

  3. ABP架构学习系列二:ABP中配置的注册和初始化

    一.手工搭建平台 1.创建项目 创建MVC5项目,手动引入Abp.Abp.Web.Abp.Web.Mvc.Abp.Web.Api 使用nuget添加Newtonsoft.Json.Castle.Cor ...

  4. linux网路编程:字节序(大端、小端、网络、主机)

    字节序:就是数据在内存中的存放顺序,也可称之为端模式. 大端模式和小端模式的定义 1) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端. 2) Big-End ...

  5. K:Union-Find(并查集)算法

    相关介绍:  并查集的相关算法,是我见过的,最为之有趣的算法之一.并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题.其相关的实现代码较为简短,实现思想也 ...

  6. win10安装Tensorflow

    win10安装Tensorflow 前提: 保证你的pip>=8.1版本 否则利用python -m pip install -U pip  进行升级,或下载pip源文件 确定你的显卡是否支持c ...

  7. jsp数据

    ---恢复内容开始--- JSP 是什么 JSP全称Java Server Pages,是一种动态网页开发技术.它使用JSP标签在HTML网页中插入Java代码.标签通常以<%开头以%>结 ...

  8. NPOI json转Excel DataTable转Excel ,Excel转DataTable

    JsonToExcel: public static void JsonToExcel(List<Dictionary<string, object>> json, strin ...

  9. Zabbix实战-简易教程(7)--监控第一台host

    一.安装 agent 1.1 Agent分布 1.2 Agent安装 基础模板安装方法: wget -qO- http://zbxinstall.168.com:18888/base/agent-in ...

  10. 使用TensorFlow中的Batch Normalization

    问题 训练神经网络是一个很复杂的过程,在前面提到了深度学习中常用的激活函数,例如ELU或者Relu的变体能够在开始训练的时候很大程度上减少梯度消失或者爆炸问题.但是却不能保证在训练过程中不出现该问题, ...