在 java5 以后, 我们接触到了线程原子性操作, 也就是在修改时我们只需要保证它的那个瞬间是安全的即可, 经过相应的包装后可以再处理对象的并发修改, 本文总结一下 Atomic 系列的类的使用方法, 其中包含:
原子更新类型 | 名称 | 描述 |
---|---|---|
基本类型 | AtomicBoolean | 原子更新布尔类型 |
基本类型 | AtomicInteger | 原子更新整型 |
基本类型 | AtomicLong | 原子更新长整型 |
数组类型 | AtomicIntegerArray | 原子更新整型数组里的元素 |
数组类型 | AtomicLongArray | 原子更新长整型数组里的元素 |
数组类型 | AtomicReferenceArray | 原子更新引用类型数组的元素 |
数组类型 | AtomicBooleanArray | 原子更新布尔类型数组的元素 |
引用类型 | AtomicReference | 原子更新引用类型 |
引用类型 | AtomicReferenceFieldUpdater | 原子更新引用类型里的字段 |
引用类型 | AtomicMarkableReference | 原子更新带有标记位的引用类型。可以原子更新一个布尔类型的标记位和应用类型 |
字段类型 | AtomicIntegerFieldUpdater | 原子更新整型的字段的更新器 |
字段类型 | AtomicLongFieldUpdater | 原子更新长整型字段的更新器 |
字段类型 | AtomicStampedReference | 原子更新带有版本号的引用类型。该类将整型数值与引用关联起来,可用于原子的更新数据和数据的版本号,可以解决使用 CAS 进行原子更新时可能出现的 ABA 问题。 |
1. 基本类型的使用
- public class AtomicTest {
- /**
- * 常见的方法列表
- *
- * @see AtomicInteger#get() 直接返回值
- * @see AtomicInteger#getAndAdd(int) 增加指定的数据, 返回变化前的数据
- * @see AtomicInteger#getAndDecrement() 减少 1, 返回减少前的数据
- * @see AtomicInteger#getAndIncrement() 增加 1, 返回增加前的数据
- * @see AtomicInteger#getAndSet(int) 设置指定的数据, 返回设置前的数据
- * @see AtomicInteger#addAndGet(int) 增加指定的数据后返回增加后的数据
- * @see AtomicInteger#decrementAndGet() 减少 1, 返回减少后的值
- * @see AtomicInteger#incrementAndGet() 增加 1, 返回增加后的值
- * @see AtomicInteger#lazySet(int) 仅仅当 get 时才会 set
- * @see AtomicInteger#compareAndSet(int, int) 尝试新增后对比, 若增加成功则返回 true 否则返回 false
- **/
- public static void main(String[] args) {
- final AtomicTicket ticket = new AtomicTicket();
- for (int i = 0; i <3; i++) {
- new Thread(new Runnable() {
- @Override
- public void run() {
- while (ticket.getCount()> 0) {
- System.out.println(Thread.currentThread().getName() + "count:" + ticket.decrement());
- }
- }
- }).start();
- }
- }
- }
- class AtomicTicket {
- public AtomicInteger count = new AtomicInteger(100);
- public int decrement() {
- return count.getAndDecrement();
- }
- public int getCount() {
- return count.get();
- }
- }
- Thread-0 count: 100
- Thread-2 count: 98
- Thread-1 count: 99
- Thread-2 count: 96
- Thread-0 count: 97
- Thread-2 count: 94
- Thread-2 count: 92
- Thread-1 count: 95
中间省略...
- Thread-1 count: 12
- Thread-2 count: 7
- Thread-0 count: 9
- Thread-2 count: 5
- Thread-1 count: 6
- Thread-2 count: 3
- Thread-0 count: 4
- Thread-2 count: 1
- Thread-1 count: 2
2. 数组类型的使用
- public class AtomicIntegerArrayTest {
- /**
- * 常见的方法列表
- * @see AtomicIntegerArray#addAndGet(int, int) 执行加法, 第一个参数为数组的下标, 第二个参数为增加的数量, 返回增加后的结果
- * @see AtomicIntegerArray#compareAndSet(int, int, int) 对比修改, 参数 1: 数组下标, 参数 2: 原始值, 参数 3, 修改目标值, 修改成功返回 true 否则 false
- * @see AtomicIntegerArray#decrementAndGet(int) 参数为数组下标, 将数组对应数字减少 1, 返回减少后的数据
- * @see AtomicIntegerArray#incrementAndGet(int) 参数为数组下标, 将数组对应数字增加 1, 返回增加后的数据
- *
- * @see AtomicIntegerArray#getAndAdd(int, int) 和 addAndGet 类似, 区别是返回值是变化前的数据
- * @see AtomicIntegerArray#getAndDecrement(int) 和 decrementAndGet 类似, 区别是返回变化前的数据
- * @see AtomicIntegerArray#getAndIncrement(int) 和 incrementAndGet 类似, 区别是返回变化前的数据
- * @see AtomicIntegerArray#getAndSet(int, int) 将对应下标的数字设置为指定值, 第二个参数为设置的值, 返回是变化前的数据
- */
- private final static AtomicIntegerArray ATOMIC_INTEGER_ARRAY = new AtomicIntegerArray(new int[]{1,2,3,4,5,6,7,8,9,10});
- public static void main(String []args) throws InterruptedException {
- Thread []threads = new Thread[10];
- for(int i = 0 ; i <10 ; i++) {
- final int index = i;
- threads[i] = new Thread() {
- public void run() {
- int original = ATOMIC_INTEGER_ARRAY.get(index);
- int result = ATOMIC_INTEGER_ARRAY.addAndGet(index, index + 1);
- System.out.println("currentThread:" + Thread.currentThread().getName() + ", 原始值为:" + original + ", 增加后的结果为:" + result);
- }
- };
- threads[i].start();
- }
- for(Thread thread : threads) {
- thread.join();
- }
- System.out.println("=========================>\n 执行已经完成, 结果列表:");
- for(int i = 0 ; i <ATOMIC_INTEGER_ARRAY.length() ; i++) {
- System.out.println(ATOMIC_INTEGER_ARRAY.get(i));
- }
- }
- }
currentThread:Thread-0 , 原始值为: 1, 增加后的结果为: 2
currentThread:Thread-3 , 原始值为: 4, 增加后的结果为: 8
currentThread:Thread-2 , 原始值为: 3, 增加后的结果为: 6
currentThread:Thread-1 , 原始值为: 2, 增加后的结果为: 4
currentThread:Thread-5 , 原始值为: 6, 增加后的结果为: 12
currentThread:Thread-4 , 原始值为: 5, 增加后的结果为: 10
currentThread:Thread-6 , 原始值为: 7, 增加后的结果为: 14
currentThread:Thread-7 , 原始值为: 8, 增加后的结果为: 16
currentThread:Thread-8 , 原始值为: 9, 增加后的结果为: 18
currentThread:Thread-9 , 原始值为: 10, 增加后的结果为: 20
=========================>
执行已经完成, 结果列表:
- 2
- 4
- 6
- 8
- 10
- 12
- 14
- 16
- 18
- 20
3. 引用类型的使用
- public class AtomicReferenceTest {
- public static void main(String[] args) {
- People people1 =new People("Bom", 0);
- People people2 =new People("Tom",10);
- // 先初始化一个值, 如果不初始化则默认值为 null
- AtomicReference<People> reference = new AtomicReference<>(people1);
- People people3 = reference.get();
- if (people3.equals(people1)) {
- System.out.println("people3:" + people3);
- } else {
- System.out.println("else:" + people3);
- }
- /**
- * 当前值: 拿当前值和 reference.get() 获取到的值去比较, 如果相等则 true 并更新值为期望值
- * 期望值: 如果返回 true 则更新为期望值, 如果返回 false 则不更新值
- */
- boolean b = reference.compareAndSet(null, people2);
- System.out.println("myClass.main-"+b+"--"+reference.get());
- boolean b1 = reference.compareAndSet(people1, people2);
- System.out.println("myClass.main-"+b1+"--"+reference.get());
- new Thread(new Runnable() {
- @Override
- public void run() {
- System.out.println(Thread.currentThread().getName());
- People people = reference.get();
- people.setName("Tom"+Thread.currentThread().getName());
- people.setAge(people.getAge()+1);
- reference.getAndSet(people);
- System.out.println(Thread.currentThread().getName()+reference.get().toString());
- }
- }).start();
- new Thread(new Runnable() {
- @Override
- public void run() {
- System.out.println(Thread.currentThread().getName());
- People people = reference.get();
- people.setName("Tom"+Thread.currentThread().getName());
- people.setAge(people.getAge()+4);
- reference.getAndSet(people);
- System.out.println(Thread.currentThread().getName()+reference.get().toString());
- }
- }).start();
- }
- }
- class People {
- private String name;
- private int age;
- public People(String name, int age) {
- this.name = name;
- this.age = age;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- @Override
- public String toString() {
- return "People{" +
- "name='" + name + '\'' +
- ", age=" + age +
- '}';
- }
- }
4. 字段类型的使用
- public class AtomicIntegerFieldUpdaterTest {
- /**
- * 可以直接访问对应的变量, 进行修改和处理
- * 条件: 要在可访问的区域内, 如果是 private 或挎包访问 default 类型以及非父亲类的 protected 均无法访问到
- * 其次访问对象不能是 static 类型的变量 (因为在计算属性的偏移量的时候无法计算), 也不能是 final 类型的变量 (因为根本无法修改), 必须是普通的成员变量
- * <p>
- * 方法 (说明上和 AtomicInteger 几乎一致, 唯一的区别是第一个参数需要传入对象的引用)
- *
- * @see AtomicIntegerFieldUpdater#addAndGet(Object, int)
- * @see AtomicIntegerFieldUpdater#compareAndSet(Object, int, int)
- * @see AtomicIntegerFieldUpdater#decrementAndGet(Object)
- * @see AtomicIntegerFieldUpdater#incrementAndGet(Object)
- * @see AtomicIntegerFieldUpdater#getAndAdd(Object, int)
- * @see AtomicIntegerFieldUpdater#getAndDecrement(Object)
- * @see AtomicIntegerFieldUpdater#getAndIncrement(Object)
- * @see AtomicIntegerFieldUpdater#getAndSet(Object, int)
- */
- public final static AtomicIntegerFieldUpdater<A> ATOMIC_INTEGER_UPDATER = AtomicIntegerFieldUpdater.newUpdater(A.class, "intValue");
- public static void main(String[] args) {
- final A a = new A();
- for (int i = 0; i < 10; i++) {
- new Thread() {
- public void run() {
- System.out.println(
- Thread.currentThread().getName() + " " + ATOMIC_INTEGER_UPDATER.get(a));
- ATOMIC_INTEGER_UPDATER.addAndGet(a, 11);
- System.out.println(
- Thread.currentThread().getName() + " " + ATOMIC_INTEGER_UPDATER.get(a));
- if (ATOMIC_INTEGER_UPDATER.compareAndSet(a, ATOMIC_INTEGER_UPDATER.get(a), 120)) {
- System.out.println(Thread.currentThread().getName() + "对应的值做了修改!");
- }
- System.out.println(
- Thread.currentThread().getName() + " " + ATOMIC_INTEGER_UPDATER.get(a));
- }
- }.start();
- }
- }
- static class A {
- volatile int intValue = 100;
- }
- }
- Thread-0 100
- Thread-2 100
- Thread-1 100
- Thread-2 122
- Thread-3 111
- Thread-5 120
- Thread-0 111
- Thread-5 142
- Thread-3 131
Thread-2 对应的值做了修改!
- Thread-2 120
- Thread-8 120
- Thread-4 133
- Thread-1 133
- Thread-9 142
- Thread-4 142
Thread-4 对应的值做了修改!
Thread-8 131
Thread-3 对应的值做了修改!
- Thread-3 120
- Thread-7 120
- Thread-7 131
Thread-5 对应的值做了修改!
- Thread-5 120
- Thread-6 120
Thread-0 对应的值做了修改!
Thread-6 131
Thread-7 对应的值做了修改!
Thread-8 对应的值做了修改!
- Thread-4 120
- Thread-9 131
Thread-1 对应的值做了修改!
Thread-9 对应的值做了修改!
- Thread-8 120
- Thread-7 120
Thread-6 对应的值做了修改!
- Thread-0 131
- Thread-6 120
- Thread-9 120
- Thread-1 120
来源: http://www.jianshu.com/p/3851f52d3b30