`
luliangy
  • 浏览: 95137 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

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);

}

 

 

分享到:
评论

相关推荐

    Java并发编程系列- volatile

    Java并发编程系列- volatile;Java并发编程系列- volatile;Java并发编程系列- volatile;Java并发编程系列- volatile;Java并发编程系列- volatile;

    Java并发编程:volatile关键字解析

    Java并发编程:volatile关键字解析

    Java并发编程(5)volatile变量修饰符-意料之外

    Java并发编程(5)volatile变量修饰符—意料之外的问题(含代码)编程开发技术共6页.pdf.zip

    Java 多线程与并发(5-26)-关键字- volatile详解.pdf

    Java 多线程与并发(5_26)-关键字_ volatile详解

    Java并发编程实战

    3.1.4 Volatile变量 3.2 发布与逸出 3.3 线程封闭 3.3.1 Ad-hoc线程封闭 3.3.2 栈封闭 3.3.3 ThreadLocal类 3.4 不变性 3.4.1 Final域 3.4.2 示例:使用Volatile类型来发布不可变对象 3.5 安全发布 3.5.1...

    Java并发编程的艺术.md

    volatile的使用优化:共享变量会被频繁读写时,可以通过追加为64字节以提高并发编程的效率。因为目前主流处理器高速缓存行是64个字节宽,不支持部分填充缓存行,通过追加到64字节的方式填满高速缓冲区的缓存行,避免...

    Java 并发核心编程

    本文的主题是关于具有java语言风格的Thread、synchronized、volatile,以及J2SE5中新增的概念,如锁(Lock)、原子性(Atomics)、并发集合类、线程协作摘要、Executors。开发者通过这些基础的接口可以构建高并发、线程...

    java并发编程

    本书全面介绍了如何使用Java 2平台进行并发编程,较上一版新增和扩展的内容包括:, ·存储模型 ·取消 ·可移植的并行编程 ·实现并发控制的工具类, Java平台提供了一套广泛而功能强大的api,工具和技术。...

    Java 并发编程实战

    3.1.4 Volatile变量 3.2 发布与逸出 3.3 线程封闭 3.3.1 Ad-hoc线程封闭 3.3.2 栈封闭 3.3.3 ThreadLocal类 3.4 不变性 3.4.1 Final域 3.4.2 示例:使用Volatile类型来发布不可变对象 3.5 安全发布 3.5.1...

    并发编程-volatile使用精讲.pdf

    并发编程-volatile使用精讲.pdf

    java并发编程与内存模型

    描述java并发编程原理 一.内存模型的相关概念 二.并发编程中的三个概念 三.Java内存模型 四..深入剖析volatile关键字 五.使用volatile关键字的场景

    Java并发编程:设计原则与模式(第二版)

    java并发方面的两大名著之一。读者将通过使用java.lang.thread类、synchronized和volatile关键字,以及wait、notify和notifyall方法,学习如何初始化、控制和协调并发操作。此外,本书还提供了有关并发编程的全方位...

    java并发编程面试题

    java并发编程 基础知识,守护线程与线程, 并行和并发有什么区别? 什么是上下文切换? 线程和进程区别 什么是线程和进程? 创建线程有哪几种方式?,如何避免线程死锁 线程的 run()和 start()有什么区别? 什么是 ...

    Java并发编程原理与实战

    多种创建线程的方式案例演示(一)带返回值的方式.mp4 多种创建线程的方式案例演示(二)使用线程池.mp4 Spring对并发的支持:Spring的异步任务.mp4 使用jdk8提供的lambda进行并行计算.mp4 了解多线程所带来的安全...

    Java并发编程学习笔记

    7、并发工具类CountDownLatch 、CyclicBarrier和Semaphore底层实现原理 8、线程池原理和如何使用线程池 9、ThreadLocal 为什么会内存泄漏 10、Volatile底层实现原理 11、AQS源码分析 12、CAS原理分析和使用场景 13、...

    Java-并发(Concurrent)编程

    资源概要:1,多线程;2,synchronized;3,volatile;4,多线程在JVM中的实现...原子类Atomic-CAS及其实现原理 锁Lock-AQS核心原理剖析 并发工具类、并发容器、阻塞队列 线程池原理剖析 线程池案例-Web容器-压力测试

    龙果 java并发编程原理实战

    龙果 java并发编程原理实战 第2节理解多线程与并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四...

    Java并发编程-volatile可见性详解

    主要介绍了Java并发编程-volatile可见性详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

Global site tag (gtag.js) - Google Analytics