什么是原子操作
不可被中断的一个或者一系列操作
实现原子操作的方式
Java可以通过锁和循环CAS的方式实现原子操作
CAS( Compare And Swap ) 为什么要有CAS?
Compare And Swap就是比较并且交换的一个原子操作,由Cpu在指令级别上进行保证。
为什么要有CAS:因为通过锁实现原子操作时,其他线程必须等待已经获得锁的线程运行完以后才能获得资源,这样就会占用系统的大量资源
CAS包含哪些参数?
CAS包含三个参数:1、变量所在内存地址V;2、变量对应的值A;3、我们将要修改的值B。如果说V上的变量的值是A的话,就用B重新赋值,如果不是A,那就什么事也不做,操作的返回结果原值是多少。
循环CAS:在一个(死)循环【for(;;)】里不断进行CAS操作,直到成功为止(自旋操作即死循环)。
CAS实现原子操作的三大问题
1、 ABA问题:其他的线程把值改成了B,很快改成了A,原子操作的线程发现值是A就修改,这样会有问题。解决ABA,引入版本号:1A-》2C-》3A
2、 循环时间很长的话,cpu的负荷比较大
3、 对一个变量进行操作可以,同时操作多个共享变量有点麻烦
CAS线程安全(面试点)
通过硬件层面的阻塞实现原子操作的安全
原子更新基本类型类
AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference。
AtomicInteger的常用方法如下
·int addAndGet(int delta):
·boolean compareAndSet(int expect,int update):
·int getAndIncrement(): 原子递增,但是返回的是自增以前的值
incrementAndGet原子递增,但是返回的是自增以后的值
·int getAndSet(int newValue):
1 package com.lgs.atomicint; 2 3 import java.util.concurrent.atomic.AtomicInteger; 4 5 /** 6 * lgs 7 * 原子操作更新整型 8 */ 9 public class AtomicIntTest { 10 static AtomicInteger ai = new AtomicInteger(1); 11 public static void main(String[] args) { 12 System.out.println(ai.getAndIncrement()); 13 ai.incrementAndGet(); 14 System.out.println(ai.get()); 15 } 16 }
输出:
1
3
原子更新数组类
AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray
AtomicIntegerArray类主要是提供原子的方式更新数组里的整型,
其常用方法如下。
·int addAndGet(int i,int delta):
·boolean compareAndSet(int i,int expect,int update):
数组通过构造方法传入,类会将数组复制一份,原数组不会发生变化。
1 package com.lgs.atomicarray; 2 3 import java.util.concurrent.atomic.AtomicIntegerArray; 4 5 /** 6 * lgs 7 * 原子操作更新数组 8 */ 9 public class AtomicArray { 10 static int[] value = new int[]{1,2}; 11 static AtomicIntegerArray ai = new AtomicIntegerArray(value); 12 13 public static void main(String[] args) { 14 ai.getAndSet(0,3); 15 System.out.println(ai.get(0)); 16 System.out.println(value[0]); 17 } 18 19 }
输出:
3
1
原子更新引用类型提供的类。
·AtomicReference: 可以解决更新多个变量的问题
·AtomicStampedReference:解决ABA问题 使用数字作为版本 关心得是有几个人改过
·AtomicMarkableReference:解决ABA问题 使用Boolean作为版本,关心的是有没有修改过
1 package com.lgs; 2 3 import java.util.concurrent.atomic.AtomicReference; 4 5 /** 6 * lgs 7 * 原子操作更新引用类型即可以同时更新多个值 8 */ 9 public class AtomicRef { 10 11 static AtomicReference<User> userAtomicReference = new AtomicReference<>(); 12 13 public static void main(String[] args) { 14 User user = new User("lgs",26); 15 userAtomicReference.set(user); 16 User updateUser = new User("ll",27); 17 userAtomicReference.compareAndSet(user,updateUser); 18 System.out.println(userAtomicReference.get().getName()); 19 System.out.println(userAtomicReference.get().getOld()); 20 } 21 22 static class User{ 23 private String name; 24 private int old; 25 26 public User(String name, int old) { 27 this.name = name; 28 this.old = old; 29 } 30 31 public String getName() { 32 return name; 33 } 34 35 public int getOld() { 36 return old; 37 } 38 } 39 40 }
输出:
ll
27
原子更新字段类
Atomic包提供了以下3个类进行原子字段更新。
·AtomicReferenceFieldUpdater:
·AtomicIntegerFieldUpdater:
·AtomicLongFieldUpdater:
违反了面向对象的原则,一般不使用