Java并发编程(一)--volatile, CAS, Atomic变量

 

JVM volatile语义:

mark:

(1)Java 内存模型不会对valatile指令的操作进行重排序:这个保证对volatile变量的操作时按照指令的出现顺序执行的。

(2)volatile变量不会被缓存在寄存器中(只有拥有线程可见)或者其他对CPU不可见的地方,每次总是从主存中读取volatile变量的结果。也就是说对于volatile变量的修改,其它线程总是可见的,并且不是使用自己线程栈内部的变量。也就是在happens-before法则中,对一个valatile变量的写操作后,其后的任何读操作理解可见此写操作的结果。

 

Volatile变量的读写

读:置本地数据无效,总是从主存中读取数据

写:更新本地数据,然后刷新主存中的数据

 

 

CAS操作:利用CPU中的特殊指令cmpxchg (intel)

CAS3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。

原子变量的实现:

首先变量是volatile的保证可见性;

对变量的更新在一个循环中实现,例如:

for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return next;
}

最少执行一次方法就可以返回,否则一直执行;

CASABA问题

比如说一个线程one从内存位置V中取出A,这时候另一个线程two也从内存中取出A,并且two进行了一些操作变成了B,然后two又将V位置的数据变成A,这时候线程one进行CAS操作发现内存中仍然是A,然后one操作成功。尽管线程oneCAS操作成功,但是不代表这个过程就是没有问题的。如果链表的头在变化了两次后恢复了原值,但是不代表链表就没有变化。因此前面提到的原子操作AtomicStampedReference/AtomicMarkableReference就很有

用了。这允许一对变化的元素进行原子操作。

 

Java通过Unsafe类通过JNI结合CPUCAS指令来完成

sun.misc.natUnsafe.cc 的源码:

 

#include <gcj/cni.h>
#include <gcj/field.h>
#include <gcj/javaprims.h>
#include <jvm.h>
#include <sun/misc/Unsafe.h>
#include <java/lang/System.h>
#include <java/lang/InterruptedException.h>
#include <java/lang/Thread.h>
#include <java/lang/Long.h>
#include "sysdep/locks.h"


// Use a spinlock for multi-word accesses

class spinlock

{

  static volatile obj_addr_t lock;

public:

spinlock ()

  {

    while (! compare_and_swap (&lock, 0, 1))

      _Jv_ThreadYield ();

  }

  ~spinlock ()

  {

    release_set (&lock, 0);

  }

};

// This is a single lock that is used for all synchronized accesses if

// the compiler can't generate inline compare-and-swap operations.  In

// most cases it'll never be used, but the i386 needs it for 64-bit

// locked accesses and so does PPC32.  It's worth building libgcj with

// target=i486 (or above) to get the inlines.

volatile obj_addr_t spinlock::lock;

static inline bool

compareAndSwap (volatile jint *addr, jint old, jint new_val)

{

  jboolean result = false;

  spinlock lock;

  if ((result = (*addr == old)))

    *addr = new_val;

  return result;

}

static inline bool

compareAndSwap (volatile jlong *addr, jlong old, jlong new_val)

{

  jboolean result = false;

  spinlock lock;

  if ((result = (*addr == old)))

    *addr = new_val;

  return result;

}

static inline bool

compareAndSwap (volatile jobject *addr, jobject old, jobject new_val)

{

  jboolean result = false;

  spinlock lock;

  if ((result = (*addr == old)))

    *addr = new_val;

  return result;

}

jlong

sun::misc::Unsafe::objectFieldOffset (::java::lang::reflect::Field *field)

{

  _Jv_Field *fld = _Jv_FromReflectedField (field);

  // FIXME: what if it is not an instance field?

  return fld->getOffset();

}

jint

sun::misc::Unsafe::arrayBaseOffset (jclass arrayClass)

{

  // FIXME: assert that arrayClass is array.

  jclass eltClass = arrayClass->getComponentType();

  return (jint)(jlong) _Jv_GetArrayElementFromElementType (NULL, eltClass);

}

jint

sun::misc::Unsafe::arrayIndexScale (jclass arrayClass)

{

  // FIXME: assert that arrayClass is array.

  jclass eltClass = arrayClass->getComponentType();

  if (eltClass->isPrimitive())

    return eltClass->size();

  return sizeof (void *);

}

// These methods are used when the compiler fails to generate inline

// versions of the compare-and-swap primitives.

jboolean

sun::misc::Unsafe::compareAndSwapInt (jobject obj, jlong offset,

                                           jint expect, jint update)

{

  jint *addr = (jint *)((char *)obj + offset);

  return compareAndSwap (addr, expect, update);

}

jboolean

sun::misc::Unsafe::compareAndSwapLong (jobject obj, jlong offset,

                                            jlong expect, jlong update)

{

  volatile jlong *addr = (jlong*)((char *) obj + offset);

  return compareAndSwap (addr, expect, update);

}

jboolean

sun::misc::Unsafe::compareAndSwapObject (jobject obj, jlong offset,

                                                jobject expect, jobject update)

{

  jobject *addr = (jobject*)((char *) obj + offset);

  return compareAndSwap (addr, expect, update);

}

void

sun::misc::Unsafe::putOrderedInt (jobject obj, jlong offset, jint value)

{

  volatile jint *addr = (jint *) ((char *) obj + offset);

  *addr = value;

}

void

sun::misc::Unsafe::putOrderedLong (jobject obj, jlong offset, jlong value)

{

  volatile jlong *addr = (jlong *) ((char *) obj + offset);

  spinlock lock;

  *addr = value;

}

void

sun::misc::Unsafe::putOrderedObject (jobject obj, jlong offset, jobject value)

{

  volatile jobject *addr = (jobject *) ((char *) obj + offset);

  *addr = value;

}

void

sun::misc::Unsafe::putIntVolatile (jobject obj, jlong offset, jint value)

{

  write_barrier ();

  volatile jint *addr = (jint *) ((char *) obj + offset);

  *addr = value;

}

void

sun::misc::Unsafe::putLongVolatile (jobject obj, jlong offset, jlong value)

{

  volatile jlong *addr = (jlong *) ((char *) obj + offset);

  spinlock lock;

  *addr = value;

}

void

sun::misc::Unsafe::putObjectVolatile (jobject obj, jlong offset, jobject value)

{

  write_barrier ();

  volatile jobject *addr = (jobject *) ((char *) obj + offset);

  *addr = value;

}

#if 0  // FIXME

void

sun::misc::Unsafe::putInt (jobject obj, jlong offset, jint value)

{

  jint *addr = (jint *) ((char *) obj + offset);

  *addr = value;

}

#endif

void

sun::misc::Unsafe::putLong (jobject obj, jlong offset, jlong value)

{

  jlong *addr = (jlong *) ((char *) obj + offset);

  spinlock lock;

  *addr = value;

}

void

sun::misc::Unsafe::putObject (jobject obj, jlong offset, jobject value)

{

  jobject *addr = (jobject *) ((char *) obj + offset);

  *addr = value;

}

jint

sun::misc::Unsafe::getIntVolatile (jobject obj, jlong offset)

{

  volatile jint *addr = (jint *) ((char *) obj + offset);

  jint result = *addr;

  read_barrier ();

  return result;

}

jobject

sun::misc::Unsafe::getObjectVolatile (jobject obj, jlong offset)

{

  volatile jobject *addr = (jobject *) ((char *) obj + offset);

  jobject result = *addr;

  read_barrier ();

  return result;

}

jlong

sun::misc::Unsafe::getLong (jobject obj, jlong offset)

{

  jlong *addr = (jlong *) ((char *) obj + offset);

  spinlock lock;

  return *addr;

}

jlong

sun::misc::Unsafe::getLongVolatile (jobject obj, jlong offset)

{

  volatile jlong *addr = (jlong *) ((char *) obj + offset);

  spinlock lock;

  return *addr;

}

void

sun::misc::Unsafe::unpark (::java::lang::Thread *thread)

{

  natThread *nt = (natThread *) thread->data;

  nt->park_helper.unpark ();

}

void

sun::misc::Unsafe::park (jboolean isAbsolute, jlong time)

{

  using namespace ::java::lang;

  Thread *thread = Thread::currentThread();

  natThread *nt = (natThread *) thread->data;

  nt->park_helper.park (isAbsolute, time);

}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值