Atomic包的作用

方便程序员在多线程环境下,无锁的进行原子操作

Atomic包核心

Atomic包里的类基本都是使用Unsafe实现的包装类,核心操作是CAS原子操作;

关于CAS

compare and swap,比较和替换技术,将预期值与当前变量的值比较(compare),如果相等则使用新值替换(swap)当前变量,否则不作操作;

现代CPU已广泛支持CAS指令,如果不支持,那么JVM将使用自旋锁,与互斥锁一样,两者都需先获取锁才能访问共享资源,但互斥锁会导致线程进入睡眠,而自旋锁会一直循环等待直到获取锁;

另外,有一点需要注意的是CAS操作中的ABA问题,即将预期值与当前变量的值比较的时候,即使相等也不能保证变量没有被修改过,因为变量可能由A变成B再变回A,解决该问题,可以给变量增加一个版本号,每次修改变量时版本号自增,比较的时候,同时比较变量的值和版本号即可;

Atomic包主要提供四种原子更新方式

  • 原子方式更新基本类型;
  • 原子方式更新数组;
  • 原子方式更新引用;
  • 原子方式更新字段;

原子方式更新基本类型

以下三个类是以原子方式更新基本类型

  • AtomicBoolean:原子更新布尔类型。
  • AtomicInteger:原子更新整型。
  • AtomicLong:原子更新长整型。

以AtomicInteger为例,

package concurrency;
import java.util.concurrent.atomic.AtomicInteger; public class AtomicIntegerTest { static AtomicInteger ai = new AtomicInteger(1); public static void main(String[] args) {
//相当于i++,返回的是旧值,看方法名就知道,先获取再自增
System.out.println(ai.getAndIncrement());
System.out.println(ai.get());
//先自增,再获取
System.out.println(ai.incrementAndGet());
System.out.println(ai.get());
//增加一个指定值,先add,再get
System.out.println(ai.addAndGet(5));
System.out.println(ai.get());
//增加一个指定值,先get,再set
System.out.println(ai.getAndSet(5));
System.out.println(ai.get());
} }

注意:Atomic包提供了三种基本类型的原子更新,剩余的Java的基本类型还有char,float和double等,其更新方式可以参考AtomicBoolean的思路来现,AtomicBoolean是把boolean转成整型再调用compareAndSwapInt进行CAS来实现的,类似的short和byte也可以转成整形,float和double可以利用Float.floatToIntBits,Double.doubleToLongBits转成整形和长整形进行相应处理;

原子方式更新数组

以下三个类是以原子方式更新数组,

  • AtomicIntegerArray:原子更新整型数组里的元素。
  • AtomicLongArray:原子更新长整型数组里的元素。
  • AtomicReferenceArray:原子更新引用类型数组里的元素。

以AtomicIntegerArray为例,其方法与AtomicInteger很像,多了个数组下标索引;

package concurrency;

import java.util.concurrent.atomic.AtomicIntegerArray;

public class AtomicIntegerArrayTest {

    static int[] valueArr = new int[] { 1, 2 };

    //AtomicIntegerArray内部会拷贝一份数组
static AtomicIntegerArray ai = new AtomicIntegerArray(valueArr); public static void main(String[] args) {
ai.getAndSet(0, 3);
//不会修改原始数组value
System.out.println(ai.get(0));
System.out.println(valueArr[0]);
} }

原子方式更新引用

以下三个类是以原子方式更新引用,与其它不同的是,更新引用可以更新多个变量,而不是一个变量;

  • AtomicReference:原子更新引用类型。
  • AtomicReferenceFieldUpdater:原子更新引用类型里的字段。
  • AtomicMarkableReference:原子更新带有标记位的引用类型。

以AtomicReference为例,

package concurrency;

import java.util.concurrent.atomic.AtomicReference;

public class AtomicReferenceTest {

    public static AtomicReference<User> atomicUserRef = new AtomicReference<User>();

    public static void main(String[] args) {
User user = new User("conan", 15);
atomicUserRef.set(user);
User updateUser = new User("Shinichi", 17);
atomicUserRef.compareAndSet(user, updateUser);
System.out.println(atomicUserRef.get().getName());
System.out.println(atomicUserRef.get().getOld());
} static class User {
private String name;
private int old; public User(String name, int old) {
this.name = name;
this.old = old;
} public String getName() {
return name;
} public int getOld() {
return old;
}
}
}

原子方式更新字段

以下三个类是以原子方式更新字段,

  • AtomicIntegerFieldUpdater:原子更新整型字段的更新器。
  • AtomicLongFieldUpdater:原子更新长整型字段的更新器。
  • AtomicStampedReference:原子更新带有版本号的引用类型,用于解决使用CAS进行原子更新时,可能出现的ABA问题。

以AtomicIntegerFieldUpdater为例,

package concurrency;

import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;

public class AtomicIntegerFieldUpdaterTest {

    private static AtomicIntegerFieldUpdater<User> a = AtomicIntegerFieldUpdater
.newUpdater(User.class, "old"); public static void main(String[] args) {
User conan = new User("conan", 10);
System.out.println(a.getAndIncrement(conan));
System.out.println(a.get(conan));
} public static class User {
private String name;
//注意需要用volatile修饰
public volatile int old; public User(String name, int old) {
this.name = name;
this.old = old;
} public String getName() {
return name;
} public int getOld() {
return old;
}
}
}

参考资料

http://ifeve.com/java-atomic/

《JAVA并发编程实战》

Java中的Atomic包的更多相关文章

  1. Java中的Atomic包使用指南

    Atomic包介绍 在Atomic包里一共有12个类,四种原子更新方式,分别是原子更新基本类型,原子更新数组,原子更新引用和原子更新字段.Atomic包里的类基本都是使用Unsafe实现的包装类. 原 ...

  2. JDK中的Atomic包中的类及使用

    引言 Java从JDK1.5开始提供了java.util.concurrent.atomic包,方便程序员在多线程环境下,无锁的进行原子操作.原子变量的底层使用了处理器提供的原子指令,但是不同的CPU ...

  3. Java并发—原子类,java.util.concurrent.atomic包(转载)

    原子类 Java从JDK 1.5开始提供了java.util.concurrent.atomic包(以下简称Atomic包),这个包中 的原子操作类提供了一种用法简单.性能高效.线程安全地更新一个变量 ...

  4. java中常用的包、类、以及包中常用的类、方法、属性----sql和text\swing

    java中常用的包.类.以及包中常用的类.方法.属性 常用的包 java.io.*; java.util.*; java.lang.*; java.sql.*; java.text.*; java.a ...

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

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

  6. java中的Atomic类

    文章目录 问题背景 Lock 使用Atomic java中的Atomic类 问题背景 在多线程环境中,我们最常遇到的问题就是变量的值进行同步.因为变量需要在多线程中进行共享,所以我们必须需要采用一定的 ...

  7. java.util.concurrent.atomic 包详解

    Atomic包的作用: 方便程序员在多线程环境下,无锁的进行原子操作 Atomic包核心: Atomic包里的类基本都是使用Unsafe实现的包装类,核心操作是CAS原子操作 关于CAS compar ...

  8. JavaSE&&JavaEE&&JavaME的区别【Java中常用的包结构】

    一.javaEEJavaSEJavaME用的同一个jar包吗? javaEE JavaSE javaME 用的JDK是同一个,开发j2SE工程的话只要有JDK就可以了,开发J2EE工程和J2ME工程除 ...

  9. Java中常见的包

    目录 JDK自带的包 第三方包 JDK自带的包 JAVA提供了强大的应用程序接口,既JAVA类库.他包含大量已经设计好的工具类,帮助程序员进行字符串处理.绘图.数学计算和网络应用等方面的工作.下面简单 ...

随机推荐

  1. CDH安装失败了,如何重新安装

    1> 删除Agent节点的UUID # rm -rf /opt/cm-5.4.7/lib/cloudera-scm-agent/* 2>  清空主节点CM数据库 进入主节点的Mysql数据 ...

  2. Java内存模型深度解析:重排序 --转

    原文地址:http://www.codeceo.com/article/java-memeory-2.html 数据依赖性 如果两个操作访问同一个变量,且这两个操作中有一个为写操作,此时这两个操作之间 ...

  3. iOS 使用EZAudio库生成wav出错的情况

    使用EZAudio库 录M4A格式可以参考该库例子中的代码. 录wav格式得改下源码.看下面的代码 AVAudioSession *session = [AVAudioSession sharedIn ...

  4. ZOJ Problem Set - 1337 Pi 最大公约数

    这道题目的关键在于怎么求两个整数的最大公约数,这里正好复习一下以前的知识,如下: 1.设整数a和b 2.如果a和b都为0,则二者的最大公约数不存在 3.如果a或b等于0,则二者的最大公约数为非0的一个 ...

  5. 主机巡检脚本:OSWatcher.sh

    主机巡检脚本:OSWatcher.sh 2016-09-26更新,目前该脚本只支持Linux操作系统,后续有需求可以继续完善. 注意: 经测试,普通用户执行脚本可以顺利执行前9项检查: 第10项,普通 ...

  6. java多线程--信号量Semaphore的使用

    Semaphore可以控制某个共享资源可被同时访问的次数,即可以维护当前访问某一共享资源的线程个数,并提供了同步机制.例如控制某一个文件允许的并发访问的数量. 例如网吧里有100台机器,那么最多只能提 ...

  7. SSH整合时执行hibernate查询报错:java.lang.ClassCastException: com.ch.hibernate.Department_$$_javassist_0 cannot be cast to javassist.util.proxy

    今天在整合ssh三个框架时,有一个功能,是查询所有员工信息,且员工表和部门表是多对一的映射关系,代码能正常运行到查询得到一个List集合,但在页面展示的时候,就报异常了, java.lang.Clas ...

  8. WebGIS中基于AGS的画圆查询简析以及通过Polygon来构造圆的算法

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.背景 某个项目需求中需要在前端进行画圆查询,将圆范围上的多边形要素 ...

  9. reactjs学习之路

    正式开始react的学习 1.react中组件的首字母如果是大写就会当成自定义组件,如果是小写就会当成DOM的自带元素名.如果你自定义组件名称首字母是小写不会报错,但是无法显示. 2.自定义组件的re ...

  10. Dapper简明教程

    Dapper是一款轻量级的ORM框架,有关Dapper优缺点的文章网上一大堆,这里小编就不再赘述啦.下面直接进入正题: 使用前准备 添加对Dapper的引用 在使用Dapper之前,我们要首先添加对D ...