java中的13个原子操作类
当程序更新一个变量时,如果多线程同时更新这个变量,可能得到期待之外的值。java1.5开始提供了atomic包,可以更简单高效安全的更新一个变量。atomic类基本都是Unsafe实现的包装类
4中类型的原子更新方式:
- 原子更新基本类型
- 原子更新数组
- 原子更新引用
- 原子更新属性
原子更新基本类型
- AtomicBoolean
- AtomicInteger
- AtomicLong
三个类的方法几乎一模一样,以AtomicInteger举例
- int addAndGet(int):返回新值
- boolean compareAndSet(int expect,int update)
- int getAndIncrement:以原子方式加1,这里返回的是自增前的值
- void lazySet(int):使用lazySet后,可能导致其他线程在之后的一段时间内还是可以读到旧的值
- int getAndSet:返回旧值
/**
* Atomically increments by one the current value.
*
* @return the previous value
*/
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
原子更新数组
- AtomicIntegerArray
- AtomicLongArray
- AtomicReferenceArray:原子更新引用数据类型的元素
常用方法
- int addAndGet(int i,int delta):以原子方式将输入的值与数组中的索引i的元素相加
- boolean compareAndset(int i , int expect, int update):如果当前值等于预期值,则以原子方式将数组位置i的元素设置成update值
数组通过构造方法传递进去,然后AtomicIntegerArray将数组复制一份,所以AtomicIntegerArray对内部数组进行修改时,不会影响传入的数组。
原子引用类型
如果需要更新多个变量就需要原子引用变量了
AtomicReference
AtomicReferenceFieldUpdater:原子更新引用类型里的字段。
原子更新字段类
如果需要原子的更新某个类的某个字段时,就需要使用原子更新字段类,Atomic包提供一下3个类进行原子字段更新:
- AtomicIntegerFieldUpdater
- AtomicLongFieldUpdater
- AtomicStampedReference
private static AtomicIntegerFieldUpdater<User> updater = AtomicIntegerFieldUpdater.newUpdater(User.class, "old");
public static void main(String[] args) {
// 设置柯南的年龄10岁
User c = new User("conan", 10);
// 柯南涨了一岁
System.out.println(updater.getAndIncrement(c));
// 查询现在的年龄
System.out.println(c.getOld());
}
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 void setName(String name) {
this.name = name;
}
public int getOld() {
return old;
}
public void setOld(int old) {
this.old = old;
}
}
- updater方法都是抽象类,需要先使用静态方法创建一个更新器,并且设置想要的更新的类和属性。
- 更新类的字段必须使用public volatile修饰符