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 cn.com.example.concurrent.atomic;

import java.util.concurrent.atomic.AtomicInteger;

/**
* Created by Jack on 2017/1/7.
*/
public class AtomicIntegerTest extends Thread { private AtomicInteger atomicInteger; public AtomicIntegerTest(AtomicInteger atomicInteger) {
this.atomicInteger = atomicInteger;
} @Override
public void run() {
int i = atomicInteger.incrementAndGet();
System.out.println("generated out number:" + i);
} public static void main(String[] args) {
AtomicInteger counter = new AtomicInteger();
for (int i = 0; i < 10; i++) {//10个线程
new AtomicIntegerTest(counter).start();
}
}
}

输出:

generated  out number:1
generated out number:2
generated out number:3
generated out number:4
generated out number:5
generated out number:6
generated out number:7
generated out number:8
generated out number:9
generated out number:10

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

原子方式更新数组

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

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

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

package cn.com.example.concurrent.atomic;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicIntegerArray; /**
* Created by Jack on 2017/1/7.
*/
public class AtomicIntegerArrayTest {
private static int threadCount = 1000;
private static CountDownLatch countDown = new CountDownLatch(threadCount);
static int[] values = new int[10];
static AtomicIntegerArray ai = new AtomicIntegerArray(values); private static class Counter implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
for (int j = 0; j < 10; j++) {//所有元素+1
ai.getAndIncrement(j);
}
}
countDown.countDown();
}
} public static void main(String[] args) throws InterruptedException {
Thread[] threads = new Thread[threadCount];
for (int i = 0; i < threadCount; i++) {
threads[i] = new Thread(new Counter());
}
for (int i = 0; i < threadCount; i++) {
threads[i].start();
}
countDown.await();
for (int i = 0; i < 10; i++) {
System.out.println(ai.get(i) + " ");
}
System.out.println();
for (int i = 0; i < 10; i++) {
System.out.println(values[i] + " ");
}
}
}

输出:

100000
100000
100000
100000
100000
100000
100000
100000
100000
100000 0
0
0
0
0
0
0
0
0
0

需要注意的是,数组value通过构造方法传递进去,然后AtomicIntegerArray会将当前数组复制一份,所以当AtomicIntegerArray对内部的数组元素进行修改时,不会影响传入的数组。

原子方式更新引用

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

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

以AtomicReference为例

package cn.com.example.concurrent.atomic;

import java.util.concurrent.atomic.AtomicReference;

/**
* Created by Jack on 2017/1/7.
*/
public class AtomicReferenceTest {
public static void main(String[] args) { // 创建两个Person对象,它们的id分别是101和102。
Person p1 = new Person(101);
Person p2 = new Person(102);
// 新建AtomicReference对象,初始化它的值为p1对象
AtomicReference ar = new AtomicReference(p1);
// 通过CAS设置ar。如果ar的值为p1的话,则将其设置为p2。
ar.compareAndSet(p1, p2); Person p3 = (Person) ar.get();
System.out.println("p3 is " + p3);
System.out.println("p3.equals(p1)=" + p3.equals(p1));
}
} class Person {
volatile long id; public Person(long id) {
this.id = id;
} public String toString() {
return "id:" + id;
}
}

输出:

p3 is id:102
p3.equals(p1)=false

新建AtomicReference对象ar时,将它初始化为p1。
紧接着,通过CAS函数对它进行设置。如果ar的值为p1的话,则将其设置为p2。
最后,获取ar对应的对象,并打印结果。p3.equals(p1)的结果为false,这是因为Person并没有覆盖equals()方法,而是采用继承自Object.java的equals()方法;而Object.java中的equals()实际上是调用"=="去比较两个对象,即比较两个对象的地址是否相等。

原子方式更新字段

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

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

以AtomicIntegerFieldUpdater为例

package cn.com.example.concurrent.atomic;

import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;

/**
* Created by Jack on 2017/1/7.
*/
public class AtomicIntegerFieldUpdaterTest { // 创建原子更新器,并设置需要更新的对象类和对象的属性
private static AtomicIntegerFieldUpdater<User> a = AtomicIntegerFieldUpdater.newUpdater(User.class, "old"); public static void main(String[] args) throws InterruptedException {
// 设置柯南的年龄是10岁
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;
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;
}
}
}

输出:

10
11

注意: old 需要声明为 volatile

java.util.concurrent.atomic 包详解的更多相关文章

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

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

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

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

  3. 《java.util.concurrent 包源码阅读》02 关于java.util.concurrent.atomic包

    Aomic数据类型有四种类型:AomicBoolean, AomicInteger, AomicLong, 和AomicReferrence(针对Object的)以及它们的数组类型, 还有一个特殊的A ...

  4. 并发之java.util.concurrent.atomic原子操作类包

    15.JDK1.8的Java.util.concurrent.atomic包小结 14.Java中Atomic包的原理和分析 13.java.util.concurrent.atomic原子操作类包 ...

  5. JDK源码学习之 java.util.concurrent.automic包

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

  6. java.util.concurrent.atomic 类包详解

    java.util.concurrent包分成了三个部分,分别是java.util.concurrent.java.util.concurrent.atomic和java.util.concurren ...

  7. java并发编程:线程安全管理类--原子包--java.util.concurrent.atomic

    java.util.concurrent.atomic 的描述 AtomicBoolean 可以用原子方式更新的 boolean 值. AtomicInteger 可以用原子方式更新的 int 值. ...

  8. Java多线程:CAS与java.util.concurrent.atomic

    锁的几种概念 悲观锁 总是假设最坏的情况,每次获取数据都认为别人会修改,所以拿数据时会上锁,一直到释放锁不允许其他线程修改数据.Java中如synchronized和reentrantLock就是这种 ...

  9. 原子类java.util.concurrent.atomic.*原理分析

    原子类java.util.concurrent.atomic.*原理分析 在并发编程下,原子操作类的应用可以说是无处不在的.为解决线程安全的读写提供了很大的便利. 原子类保证原子的两个关键的点就是:可 ...

随机推荐

  1. <input />文字方框中,字体颜色的变化 要求默认的字体颜色是灰色,当要输入字时,字体是正常的黑色

    <input type="text" name="address" size="60" maxlength="60" ...

  2. [译]SSAS下玩转PowerShell(三)

    在第一篇中简单介绍了PowerShell,包含基本的一些命令,以及如何打开PowerShell,并且导航到SSAS对象.第二篇中学习了如何使用变量根据当前日期创建SSAS备份,以及如何运行MDX和XM ...

  3. storm集群部署和配置过程详解

      先整体介绍一下搭建storm集群的步骤: 设置zookeeper集群 安装依赖到所有nimbus和worker节点 下载并解压storm发布版本到所有nimbus和worker节点 配置storm ...

  4. 朴素贝叶斯算法的python实现

    朴素贝叶斯 算法优缺点 优点:在数据较少的情况下依然有效,可以处理多类别问题 缺点:对输入数据的准备方式敏感 适用数据类型:标称型数据 算法思想: 朴素贝叶斯比如我们想判断一个邮件是不是垃圾邮件,那么 ...

  5. java基础(二)

    1.equals()方法是可以重写的,因此说equals方法是判断两个对象的值是否相等是不完全正确的,当重写方法时可以定义自己的相等规则. 2.Java中的类可以包含六中元素;属性.方法.代码块.内部 ...

  6. 将android模拟器上的db文件拷贝到电脑上

    1. db文件在android手机中的存储地址一般都是/data/data/packname/databases/db_file. 2.打开cmd,运行 adb shell ,使用root权限 3.通 ...

  7. hdu4632 Palindrome subsequence (区间dp)

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=4632 题意:求回文串子串的的个数. 思路:看转移方程就能理解了. dp[i][j] 表示区 ...

  8. Leetcode Simplify Path

    Given an absolute path for a file (Unix-style), simplify it. For example,path = "/home/", ...

  9. 单元测试地二蛋 先弄个两个原生模块1个原始的一个jq插件

    放羊测试测完了再测这两个瞎搞的下拉列表组建 看看从单元测试模块化的角度组建会写成啥样 1:ajax请求 简单文本     2:1个页面多个实例     3:复杂展示+自定义点击+自定义处理函数     ...

  10. ZeroMQ接口函数之 :zmq_strerror - 获取ZMQ错误描述字符串

    ZeroMQ 官方地址 :http://api.zeromq.org/4-0:zmq_strerror zmq_strerror(3) ØMQ Manual - ØMQ/4.1.0 Name zmq_ ...