之前的章节中,我们已经学习了关于并发编程的许多概念,用法。
但是,多线程比较负责,不到不得已,不应该自己使用太频繁,建议使用java已封装好的各种java类来进行实现。
J.U.C包基本内容
这几天先学习下原子操作类Atomic:
今天,先一起学习下基础原子类的并发操作类。
基础类型的原子操作类
主要是以下三个:
AtomicBoolean,AtomicInteger,AtomicLong,分别对应基础类型bool,int,long的操作原子性,因三个类实现比较类似。
下面我们以AtomicInteger类举个栗子说明:
AtomicInteger方法摘要:
intaddAndGet(int delta)
以原子方式将给定值与当前值相加,返回修改后的值。
booleancompareAndSet(int expect, int update)
如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。
intdecrementAndGet()
以原子方式将当前值减 1,返回修改后的值,相当于--i。
doubledoubleValue()
以 double 形式返回指定的数值。
floatfloatValue()
以 float 形式返回指定的数值。
intget()
获取当前值。
intgetAndAdd(int delta)
以原子方式将给定值与当前值相加,返回之前的值。
intgetAndDecrement()
以原子方式将当前值减 1,返回之前的值,相当于i--。
intgetAndIncrement()
以原子方式将当前值加 1,返回之前的值,相当于i++。
intgetAndSet(int newValue)
以原子方式设置为给定值,并返回旧值。
intincrementAndGet()
以原子方式将当前值加 1,返回修改后的值,相当于++i
intintValue()
以 int 形式返回指定的数值。
voidlazySet(int newValue)
最后设置为给定值,非即时方式。
longlongValue()
以 long 形式返回指定的数值。
voidset(int newValue)
设置为给定值。
StringtoString()
返回当前值的字符串表示形式。
booleanweakCompareAndSet(int expect, int update)
如果当前值 == 预期值,则以原子方式将该设置为给定的更新值。
CAS的实现方式:
举个栗子:
下面我们用其中一个方法说明实现方式:
public final int incrementAndGet() {
for (;;) {//使用循环方式,不放弃cpu使用权,不阻塞,直到成功
// 获取AtomicInteger当前对应的int值,为volatile类型,保证取到的为最新的值
int current = get();
// 将current加1
int next = current + 1;
// 通过CAS函数,更新current的值,如果和预期值不符,则不更新并继续重试,成功则返回更新后的值。
if (compareAndSet(current, next))
return next;
}
}
compareAndSet的实现:
public final boolean compareAndSet(long expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
//valueOffset,表示这个对象的value值所在内存的地址迁移量。
private static final long valueOffset;
static {
try {
} catch (Exception ex) { throw new Error(ex);
}
那么在unsafe中,如何实现CAS的操作呢?
在Unsafe类中,compareAndSwapInt是native方法,就是java中依赖操作系统和硬件的方法,具体实现在c++源码中。
而在openjdk的unsafe.cpp中,可以看到如下代码:
UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))
UnsafeWrapper("Unsafe_CompareAndSwapInt");
oop p = JNIHandles::resolve(obj);
jint* addr = (jint *) index_oop_from_field_offset_long(p, offset);
return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
UNSAFE_END
主要是用Atomic::cmpxchg实现:
inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value) {
// alternative for InterlockedCompareExchange
int mp = os::is_MP();
__asm {
mov edx, dest
mov ecx, exchange_value
mov eax, compare_value
LOCK_IF_MP(mp)
cmpxchg dword ptr [edx], ecx
}
}
如上面汇编代码所示,在此处实现了CAS思想。
1.LOCK_IF_MP判断是否是多线程处理器,如果是,则加锁,用于添加内存屏障并刷新写缓冲区到内存。
2.dword汇编指令,dword ptr [edx] 简单来说,就是获取edx中内存地址中的具体的数据值,
3.cmpxchg汇编指令,首操作数与第二操作数比较,如果相等,第二操作数(源操作数)的值装载到首操作数,标志位置1。如果不等, 首操作数的值装载到第二操作数并将标志位清0。
如上所述,java的CAS函数的功能主要是通过汇编指令cmpxchg实现的。
感兴趣的小伙伴,请关注本人公众号:暖爸的java家园
领取专属 10元无门槛券
私享最新 技术干货