java.util.concurrent.atomic 包详解
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 包详解的更多相关文章
- Java:多线程,java.util.concurrent.atomic包之AtomicInteger/AtomicLong用法
1. 背景 java.util.concurrent.atomic这个包是非常实用,解决了我们以前自己写一个同步方法来实现类似于自增长字段的问题. 在Java语言中,增量操作符(++)不是原子的,也就 ...
- Java并发—原子类,java.util.concurrent.atomic包(转载)
原子类 Java从JDK 1.5开始提供了java.util.concurrent.atomic包(以下简称Atomic包),这个包中 的原子操作类提供了一种用法简单.性能高效.线程安全地更新一个变量 ...
- 《java.util.concurrent 包源码阅读》02 关于java.util.concurrent.atomic包
Aomic数据类型有四种类型:AomicBoolean, AomicInteger, AomicLong, 和AomicReferrence(针对Object的)以及它们的数组类型, 还有一个特殊的A ...
- 并发之java.util.concurrent.atomic原子操作类包
15.JDK1.8的Java.util.concurrent.atomic包小结 14.Java中Atomic包的原理和分析 13.java.util.concurrent.atomic原子操作类包 ...
- JDK源码学习之 java.util.concurrent.automic包
一.概述 Java从JDK1.5开始提供了java.util.concurrent.atomic包,方便程序员在多线程环境下无锁的进行原子操作.原子变量的底层使用了处理器提供的原子指令,但是不同的CP ...
- java.util.concurrent.atomic 类包详解
java.util.concurrent包分成了三个部分,分别是java.util.concurrent.java.util.concurrent.atomic和java.util.concurren ...
- java并发编程:线程安全管理类--原子包--java.util.concurrent.atomic
java.util.concurrent.atomic 的描述 AtomicBoolean 可以用原子方式更新的 boolean 值. AtomicInteger 可以用原子方式更新的 int 值. ...
- Java多线程:CAS与java.util.concurrent.atomic
锁的几种概念 悲观锁 总是假设最坏的情况,每次获取数据都认为别人会修改,所以拿数据时会上锁,一直到释放锁不允许其他线程修改数据.Java中如synchronized和reentrantLock就是这种 ...
- 原子类java.util.concurrent.atomic.*原理分析
原子类java.util.concurrent.atomic.*原理分析 在并发编程下,原子操作类的应用可以说是无处不在的.为解决线程安全的读写提供了很大的便利. 原子类保证原子的两个关键的点就是:可 ...
随机推荐
- JSON&XML总结
JSON&XML: JSON----- //英译 Serialization:序列化 perform:执行 segue:继续 IOS5后 NSJSONSerialization解析 解析JSO ...
- Loadrunner监控Linux系统资源
一.安装rsh和rpcbind 1.查看是否安装:rpm -qa |grep rsh 2.安装rsh:yum -y install rsh* 3.yum -y install nfs-utils r ...
- Lattice FPGA 板子 调试笔记
最近在调试LATTICE FPGA 做的视频板子,颇不顺利,所以记录下来作为以后的参考: 1.FPGA的IO口不是所有的都是双向的,有些有特殊作用的是单向的. 在查阅 LatticeECP3-17E ...
- MongoDB 安装
年初换了个硬盘空间更大的vps,这下终于可以装MongoDB了. 1 配置包管理系统(yum) 建立 /etc/yum.repos.d/mongodb-org-3.2.repo文件.内容如下: [mo ...
- mac
command+R 刷新页面 command+shift+C 我的电脑 finder->应用程序 -> 实用程序 -> 终端 打开 cmd command+F3 显示桌面 comma ...
- [Linux]在linux中,常常用到ctrl和其他按键组合,常用的有哪些及意义呢
在linux中,常常用到ctrl和其他按键组合,常用的有哪些及意义呢? Ctrl+c 结束正在运行的程序 Ctrl+d 结束输入或退出shell Ctrl+s 暂停屏幕输出[锁住终端] Ctrl+q ...
- 复利计算--结对项目<04-11-2016> 1.0.0 lastest 阶段性完工~
结对项目:Web复利计算 搭档博客地址:25江志彬 http://www.cnblogs.com/qazwsxedcrfv/ 个人摘要: (2016-04-09-12:00)补充:之前传送门没做好, ...
- Codeforces Round #363 (Div. 2)
A题 http://codeforces.com/problemset/problem/699/A 非常的水,两个相向而行,且间距最小的点,搜一遍就是答案了. #include <cstdio& ...
- 简单CSS3动画制作
本贴已重新编辑至http://www.cnblogs.com/fastmover/p/4977358.html 最近需要用到了一些CSS3动画,基本用Animate.css(https://githu ...
- Java 根据两个经纬度坐标计算距离
public class Distance{ private static final double EARTH_RADIUS = 6378137; private static double ...