什么是原子操作?如何实现原子操作?
syn基于阻塞的锁的机制,1.被阻塞的锁的优先级很高。2.拿到所得线程一直不释放锁锁就GG.3.大量的竞争,消耗cpu,同时可能带来死锁或者其他的线程安全问题。
CAS的原理:
CAS(Compare And Swap),指令级别保证这是一个原子操作
三个运算符:一个内存地址V,一个期望值A,一个新值B.
基本思路:如果地址V上的值和期望的值A相等,就给地址V赋给新值B,如果不是,不做任何操作,循环(死循环、自旋)里不断进行CAS操作。
CAS的问题:
1.ABA问题,A–>B–>A,解决方法:版本号:A1–>B2–>A3(如果另一个线程修改V值假设原来是A,先修改成B,再修改回成A。当前线程的CAS操作无法分辨当前V值是否发生过变化,解决方法,添加版本号)
2.开销问题:循环不断执行CAS操作,如果CAS操作长期不成功,cpu不断循环,造成大量内存开销。
3.只能保证一个共享变量的原子操作。
代码示例:
public class CAS {
static AtomicInteger atomicInteger = new AtomicInteger(0);
public void increment(){
for(;;){
int i = atomicInteger.get();
boolean suc = atomicInteger.compareAndSet(i,++i);
if(suc)break;
}
}
public static void main(String[] args) {
new CAS().increment();
System.out.println(atomicInteger.get());
}
}
更新基本类型类
public class AtomicBaseTypeTest {
static AtomicInteger atomicInteger = new AtomicInteger(12);
static AtomicBoolean atomicBoolean = new AtomicBoolean(false);
static AtomicLong atomicLong = new AtomicLong(1000000000);
public static void main(String[] args) {
//Integer
System.out.println(atomicInteger.addAndGet(12));//24
System.out.println(atomicInteger.getAndAdd(12));//24
System.out.println(atomicInteger.get());//36
System.out.println(atomicInteger.compareAndSet(36,23));//true
System.out.println(atomicInteger.get());//23
//Boolean
System.out.println(atomicBoolean.getAndSet(true));//false
System.out.println(atomicBoolean.get());//true
System.out.println(atomicBoolean.compareAndSet(true,false));//true
System.out.println(atomicBoolean.compareAndSet(true,false));//false
System.out.println(atomicBoolean.get());//false
//long
System.out.println(atomicLong.addAndGet(100));//1000000100
System.out.println(atomicLong.getAndAdd(100));//1000000100
System.out.println(atomicLong.getAndSet(123456789));//1000000200
System.out.println(atomicLong.compareAndSet(123456789,987654321));//true
System.out.println(atomicLong.get());//987654321
}
}
更新数组类型类
public class AtomicArrayTest {
static AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(10);//数组长度为10,默认元素为0
static AtomicLongArray atomicLongArray = new AtomicLongArray(10);
static AtomicReferenceArray<Person> atomicReferenceArray = new AtomicReferenceArray<Person>(10);
public static void main(String[] args) {
//Integer
System.out.println(atomicIntegerArray.addAndGet(0,3));//返回更新值0+3
System.out.println(atomicIntegerArray.getAndAdd(0,4));//返回索引位置原值并更新,返回3
System.out.println(atomicIntegerArray.decrementAndGet(0));//以原子方式将索引 i 的元素减 1,0+3+4-1=6
System.out.println(atomicIntegerArray.getAndAccumulate(0,1,(int left, int right)->left+2*right));//返回前一个值6
/*i - 索引、x - 更新值、accumulatorFunction - 作用函数*/
System.out.println(atomicIntegerArray.get(0));//6+2*1=8
System.out.println(atomicIntegerArray.decrementAndGet(0));//8-1=7
System.out.println(atomicIntegerArray.updateAndGet(0,(int data)->data+1));//8+1
//AtomicLongArray类似
//Reference
Person personA = new Person("zs",12);
Person personB = new Person("ls",15);
atomicReferenceArray.set(0,personA);
System.out.println(atomicReferenceArray.get(0));
System.out.println(atomicReferenceArray.compareAndSet(0,personA,personB));
System.out.println(atomicReferenceArray.get(0));
}
private static class Person{
private String name;
private int age;
public Person(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 "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
}
更新引用类型类
public class AtomicReferenceTest {
static Person person = new Person("zs",15);
static AtomicReference<Person> atomicReference = new AtomicReference<>(person);
public static void main(String[] args) {
System.out.println(atomicReference.compareAndSet(person,new Person("wemz",15)));//true
System.out.println(atomicReference.getAndSet(new Person("ssd",20)));//Person{name='wemz', age=15}
System.out.println(atomicReference.get().getName()+"++++"+atomicReference.get().getAge());//ssd++++20
}
private static class Person{
private String name;
private int age;
public Person(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 "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
}
版本标记示例,AtomicStampedReference
:
public class AtomicStampedReferenceTest {
static AtomicStampedReference atomicStampedReference = new AtomicStampedReference(0, 0);
public static void main(String[] args) {
System.out.println(atomicStampedReference.getStamp());//0
System.out.println(atomicStampedReference.getReference());//0
new Thread(() -> {
atomicStampedReference.compareAndSet(atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
System.out.println("当前atomicStampedReference为" + atomicStampedReference.getReference() + ";时间戳为" + atomicStampedReference.getStamp());
}).start();
new Thread(() -> {
atomicStampedReference.compareAndSet(atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
System.out.println("当前atomicStampedReference为" + atomicStampedReference.getReference() + ";时间戳为" + atomicStampedReference.getStamp());
}).start();
}
}
0
0
当前atomicStampedReference为1;时间戳为1
当前atomicStampedReference为2;时间戳为2
Process finished with exit code 0