重读Java并发编程艺术(6) -Java的13个原子操作类


JDK1.5 开始提供了 Java.util.concurrent.atomic包,基本上都是使用 Unsafe 实现的包装类。

1. 原子更新基本类型类

1.1 类

  • AtomicBoolean: 原子更新布尔类型
  • AtomicInteger: 原子更新整型
  • AtomicLong: 原子更新长整型

1.2 方法

  • int addAndGet(int delta): 以原子方式将输入的数值与实例中的值(AtomicInteger里的 value)相加,并返回结果,效果类似 ++i。
  • boolean compareAndSet(int expect, int update): 如果输入的数值等于预期值,则以原子方式将该值设置为输入的值。
  • int getAndIncrement(): 以原子方式将当前值加1,注意,这里返回的是自增前的值,效果类似 i++。
  • void lazySet(int newValue): 最终会设置成 newValue,使用 LazySet设置值后,可能导致其他线程在之后的一小段时间内还是可以读到旧的值。
  • int getAndSet(int newValue): 以原子方式设置为 newValue 的值,并返回旧值。

1.3 实现原理

AtomicInteger.java源码

public final int getAndIncrement(){
	for(;;){
		int current = get();
		int next = current + 1;
		if(compareAndSet(current, next))
			return current;
	}
}
public final boolean compareAndSet(int expect, int update){
	return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

1.4 Unsafe源码

Unsafe 只提供了以下3种CAS方法,AtomicBoolean实际是先把 Boolean 转成整型,再使用 compareAndSwapInt 进行 CAS,所以原子更新 char、float和double变量也可以用类似的思路来实现。
Unsafe.java源码

/**
 * 如果当前数值是 expected,则原子地将 Java 变量更新成 x
 * @return 如果更新成功者返回 true
 */
public final native boolean compareAndSwapObject(Object o, long offset, Object expected, Object x);

public final native boolean compareAndSwapInt(Object o, long offset, int expected, Object x);

public final native boolean compareAndSwapLong(Object o, long offset, long expected, long x);

2. 原子更新数组

2.1 类

  • AtomicIntegerArray: 原子更新整型数组里的元素。
  • AtomicLongArray: 原子更新长整型数组里的元素。
  • AtomicReferenceArray: 原子更新引用类型数组里的元素。

2.2 方法

  • int addAndGet(int i, int delta): 以原子方式将输入值与数组中索引 i 的元素相加。
  • boolean compareAndSet(int i, int expect, int update): 如果当前值等于预期值,则以原子方式将数组位置 i 的元素设置成 update 值。

注意:使用带参构造方法AtomicIntegerArray(int[] value)创建对象时,会将当前value数组复制一份,所以当 AtomicIntegerArray 对内部的数组元素进行修改时,不会影响传入的数组。

3. 原子更新引用类型

3.1 类

  • AtomicReference: 原子更新引用类型
  • AtomicReferenceFieldUpdater: 原子更新引用类型里的字段
  • AtomicMarkableReference: 原子更新带有标记位的引用类型。可以原子更新一个布尔类型的标记位和引用类型。构造方法 AtomicMarkableReference(V initialRef, Boolean initialMark)。

4. 原子更新字段类

4.1 类

  • AtomicIntegerFieldUpdater: 原子更新整型的字段的更新器。
  • AtomicLongFieldUpdater: 原子更新长整型字段的更新器。
  • AtomicStampedReference: 原子更新带有版本号的引用类型。该类将整数值与引用关联起来,可以解决使用CAS进行原子更新时可能出现的ABA问题。

4.2 需要注意的点

  1. 因为原子更新字段类都是抽象类,每次使用时必须使用静态方法 newUpdate() 创建一个更新器,并且设置想要更新的类和属性。
  2. 更新类的字段(属性)必须使用 public volatile 修饰符。

4.3 示例代码

public class AtomicIntegerFieldUpdaterTest{
	//创建原子更新器,并设置需要更新的对象类和字段名
	private static AtomicIntegerFieldUpdater<User> a = AtomicIntegerFieldUpdater.newUpdater(User.class, "old");
	
	public static void main(String[] args){
		//设置柯南的年龄是10岁
		User conan = new User("conan", 10);
		//柯南长了一岁,但是仍然会输出旧的年龄
		System.out.println(a.getAndIncrement(conan));
		//输出柯南现在的年龄
		System.out.println(a.get(connan));
	}

	public static class User{
		private String name;
		//需要更新的字段必须使用 public volatile 修饰符
		public volatile int old;

		public User(String name, int old){
			this.name = name;
			this.old = old;
		}

		public String getName(){
			return name;
		}

		public int getOld(){
			return old;
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值