java并发编程之concurrent包原子类

之前的章节中,我们已经学习了关于并发编程的许多概念,用法。

但是,多线程比较负责,不到不得已,不应该自己使用太频繁,建议使用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家园

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20200114A04Y6P00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券

,,