一,java中的原子操作类型
jdk1.5开始提供了Atomic包,这个包中的原子操作类提供了一种用法简单,性能高效,线程安全的更新一个变量的方式
二,原子更新基本类型
该类用于原子的更新基本类型:
- AtomicInteger
- AtomicBoolean
- AtomicLong
/**
* @Description: 原子更新基本类型
* @Author: Kevin
* @CreateDate: 2019/7/1 21:34
* @UpdateUser: Kevin
* @UpdateDate: 2019/7/1 21:34
* @UpdateRemark: 修改内容
* @Version: 1.0
*/
public class AtomicIntergerTest {
static AtomicInteger atomicInteger = new AtomicInteger(1);
public static void main(String[] args) {
//原子的方式增加指定的值
System.out.println("--------->" + atomicInteger.addAndGet(1));
//compareAndSet(int expect,int update)如果expect = atomicInteger.get() 则将该atomicInteger.get()设置为update
System.out.println("--------->"+atomicInteger.compareAndSet(1,2)+atomicInteger.get());
//自增1,返回的是自增前的值
System.out.println("--------->"+atomicInteger.getAndIncrement());
//自减1,返回的是自减前的值
System.out.println("--------->"+atomicInteger.getAndDecrement());
//延时更新
atomicInteger.lazySet(1);
}
}
1.原子更新原理
1.getAndIncrement()原理
注意点:
- atomicInteger.compareAndSet(current,next)
这是进行原子更新操作的重点,检查当前原子值是否等于current(期望值),如果相等,就是当前原子值没有被其他线程修改,可以进行更新操作
/**
* getAndIncrement()原理
* @return
*/
public static int getAndIncrement(){
for(;;){
//获取当前原子值
int current = get();
//自增
int next = current+1;
//如果当前原子值 == current 就将当前原子值设置为next
if(atomicInteger.compareAndSet(current,next)){
//返回自增前原子值
return current;
}
}
}
2.UnSafe
作用
执行低级别,不安全的操作
使用
在java程序中无法直接使用unsafe,其构造方法是私有的,我们只能通过Unsafe的getUnsafe()方法获取该类的对象:
private static final Unsafe unsafe = Unsafe.getUnsafe();
相关具体使用:
-
修改内存
unsafe通过相关的putxxx 和getxxx方法来修改内存和获取内存中的值
-
在非java堆中分配内存
Unsafe类通过allocateMemory(long)方法分配的内存,不受Integer.MAX_VALUE的限制,并且分配在非堆内存,使用它时,需要非常谨慎,该部分内存需要手动回收,否则会产生内存泄露
-
CAS
下面提到
3.CAS
CAS,Compare and Swap即比较并交换,设计并发算法时常用到的一种技术,java.util.concurrent包全完建立在CAS之上,没有CAS也就没有此包,可见CAS的重要性。
Unsafe类中提供了compareAndSwapObject()、compareAndSwapInt()和compareAndSwapLong()这三个方法用来实现对应的CAS原子操作。在Java的并发编程中用到的CAS操作都是调用的Unsafe类的相关方法。
unsafe中的CAS
public final native boolean compareAndSwapObject(Object o,Long offset,Object expected,Object x);
public final native boolean compareAndSwapInt(Object o,Long offset,Object expected,Object x);
public final native boolean compareAndSwapLong(Object o,Long offset,Object expected,Object x);
CAS操作原理
CAS有三个操作数:内存值V、旧的预期值A、要修改的值B,当且仅当预期值A和内存值V相同时,将内存值修改为B并返回true,否则,即内存值和当前预期值不等时,则可能是其他线程修改了当前内存值,造成线程不安全的现象,所以这时。CAS什么都不做并返回false。
三,原子更新引用类型
原子更新基本类型只能更新一个变量,如果要原子更新多个变量,就需要使用这个原子更新引用类型提供的类
- AtomicReference 原子更新引用类型
- AtomicReferenceFieldUpdater 原子更新引用类型里的字段
- AtomicMarkableRefrence 原子更新带有标记位的引用类型
使用
/**
* @Auther: Kevin
* @Date:
* @ClassName:AtomicReferenceTest
* @Description: TODO
*/
public class AtomicReferenceTest {
public static AtomicReference<User> atomicReference = new AtomicReference<>();
public static void main(String[] args) {
User user = new User("kevin",15);
atomicReference.set(user);
User updateUser = new User("newKevin",20);
atomicReference.compareAndSet(user,updateUser);
System.out.println("--------->"+atomicReference.get().getName());
System.out.println("--------->"+atomicReference.get().getAge());
}
static class User{
private String name;
private int age;
public User(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;
}
}
}
四,原子更新类中字段
如果需要原子地更新某个类里的某个字段时,需要使用原子更新字段类:
- AtomicIntegerFieldUpdater
- AtomicLongFieldUpdater
- AtomicStampedFieldUpdater
/**
* @Auther: Kevin
* @Date:
* @ClassName:AtomicIntegerFiledUpdaterTest
* @Description: TODO
*/
public class AtomicIntegerFiledUpdaterTest {
public static AtomicIntegerFieldUpdater<AtomicIntegerFiledUpdaterTest.User> atomicIntegerFieldUpdater = AtomicIntegerFieldUpdater.newUpdater(AtomicIntegerFiledUpdaterTest.User.class,"age");
public static void main(String[] args) {
User user = new User("kevin",20);
System.out.println("-------->"+atomicIntegerFieldUpdater.getAndIncrement(user));
System.out.println("--------->"+atomicIntegerFieldUpdater.get(user));
}
static class User{
private String name;
private int age;
public User(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;
}
}
}
五,原子更新数组
通过原子方式来更新数组的某个元素,
- AtomicIntegerArray
- AtomicLongArray
- AtomicReferenceArray
public class AtomicIntegerArrayTest {
static int[] value = new int[]{1,2};
static AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(value);
public static void main(String[] args) {
System.out.println("--------->"+atomicIntegerArray.addAndGet(0,2));
System.out.println("--------->"+atomicIntegerArray.get(1));
System.out.println("--------->"+atomicIntegerArray.getAndSet(1,2));
}
}