`
lobin
  • 浏览: 425574 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Java CAS实现原理

 
阅读更多

Java提供了对CAS的支持。参考另一篇文章:https://lobin.iteye.com/blog/2325737

 

在JAVA中,Unsafe类针对CAS操作提供了3个方法:compareAndSwapInt、compareAndSwapLong、compareAndSwapObject,分别用于原子操作更新Java变量,第1个用于int类型,第2个用于long类型,第3个用于Object类型。这3个方法都是native方法。对应的本机实现分别为Unsafe_CompareAndSwapInt、Unsafe_CompareAndSwapLong、Unsafe_CompareAndSwapObject。参考hotspot\src\share\vm\prims\unsafe.cpp。

 

compareAndSwapInt方法定义如下:

    /**
     * Atomically update Java variable to <tt>x</tt> if it is currently
     * holding <tt>expected</tt>.
     * @return <tt>true</tt> if successful
     */
    public final native boolean compareAndSwapInt(Object o, long offset,
                                                  int expected,
                                                  int x);

compareAndSwapLong方法定义如下:

    /**
     * Atomically update Java variable to <tt>x</tt> if it is currently
     * holding <tt>expected</tt>.
     * @return <tt>true</tt> if successful
     */
    public final native boolean compareAndSwapLong(Object o, long offset,
                                                   long expected,
                                                   long x);

compareAndSwapObject方法定义如下:

    /**
     * Atomically update Java variable to <tt>x</tt> if it is currently
     * holding <tt>expected</tt>.
     * @return <tt>true</tt> if successful
     */
    public final native boolean compareAndSwapObject(Object o, long offset,
                                                     Object expected,
                                                     Object x);

这3个方法都有4个参数,第1个参数表示要更新的变量所对应的对象,第2个参数表示要更新的变量相对于变量所对应的对象的偏移位置,也就是相对于第1个参数的偏移位置,第3个变量表示期望值,也就是CAS操作中的expect值,第4个参数表示要更新的值,如果更新成功,变量的值更新为要更新的值,返回true,否则返回false。

 

对应到本机方法实现,方法函数多了两个参数env,unsafe,参考另一篇文章:https://lobin.iteye.com/admin/blogs/2312005.第一个参数是一个JNIEnv类型的指针,表示Java Runtime运行时环境,第2个参数表示Unsafe对象,通过该参数可以得到Unsafe Java对象对应的oop。

 

其中Unsafe_CompareAndSwapInt方法实现在hotspot\src\share\vm\prims\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

以上代码需要将宏展开,从代码上看,首先调用resolve函数根据obj(要更新的变量所对应的对象)得到对应的oop,然后调用index_oop_from_field_offset_long函数得到要更新的变量在内存中的地址,最后调用Atomic::cmpxchg函数执行CAS操作更新变量为x,x为要更新的值,e为期望值,在执行CAS操作是会比较实际值和e期望值是否相等,如果相等则更新。

 

 

Unsafe_CompareAndSwapLong方法实现在hotspot\src\share\vm\prims\unsafe.cpp中,代码如下:

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapLong(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jlong e, jlong x))
  UnsafeWrapper("Unsafe_CompareAndSwapLong");
  Handle p (THREAD, JNIHandles::resolve(obj));
  jlong* addr = (jlong*)(index_oop_from_field_offset_long(p(), offset));
  if (VM_Version::supports_cx8())
    return (jlong)(Atomic::cmpxchg(x, addr, e)) == e;
  else {
    jboolean success = false;
    ObjectLocker ol(p, THREAD);
    if (*addr == e) { *addr = x; success = true; }
    return success;
  }
UNSAFE_END

Unsafe_CompareAndSwapLong方法和Unsafe_CompareAndSwapInt方法总体上差不多,这里会检查JVM是否支持cmpxchg8,参考hotspot\src\share\vm\runtime\vm_version.hpp中的以下代码

// does HW support an 8-byte compare-exchange operation?
static bool supports_cx8()  
{
    return _supports_cx8;
}

在hotspot\src\cpu\x86\vm\vm_version_x86.cpp中的VM_Version::get_processor_features方法会检查JVM是否支持cmpxchg8:

void VM_Version::get_processor_features() {
    ... 
    ...
    _supports_cx8 = supports_cmpxchg8();
    ...
    ...
}

如果支持cmpxchg8的话,调用Atomic::cmpxchg函数执行CAS操作。否则的话就加锁,软件实现CAS操作。

 

Unsafe_CompareAndSwapObject方法实现在hotspot\src\share\vm\prims\unsafe.cpp中,代码如下:

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject e_h, jobject x_h))
  UnsafeWrapper("Unsafe_CompareAndSwapObject");
  oop x = JNIHandles::resolve(x_h);
  oop e = JNIHandles::resolve(e_h);
  oop p = JNIHandles::resolve(obj);
  HeapWord* addr = (HeapWord *)index_oop_from_field_offset_long(p, offset);
  if (UseCompressedOops) {
    update_barrier_set_pre((narrowOop*)addr, e);
  } else {
    update_barrier_set_pre((oop*)addr, e);
  }
  oop res = oopDesc::atomic_compare_exchange_oop(x, addr, e);
  jboolean success  = (res == e);
  if (success)
    update_barrier_set((void*)addr, x);
  return success;
UNSAFE_END

Unsafe_CompareAndSwapObject方法和上面的两个方法不一样,这里调用的是oopDesc::atomic_compare_exchange_oop函数执行CAS操作更新。

 

JVM Atomic Atomic::cmpxchg:

 

CAS操作更新byte类型

参考hotspot\src\share\vm\runtime\atomic.cpp中的代码:

jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest, jbyte compare_value) {
  assert(sizeof(jbyte) == 1, "assumption.");
  uintptr_t dest_addr = (uintptr_t)dest;
  uintptr_t offset = dest_addr % sizeof(jint);
  volatile jint* dest_int = (volatile jint*)(dest_addr - offset);
  jint cur = *dest_int;
  jbyte* cur_as_bytes = (jbyte*)(&cur);
  jint new_val = cur;
  jbyte* new_val_as_bytes = (jbyte*)(&new_val);
  new_val_as_bytes[offset] = exchange_value;
  while (cur_as_bytes[offset] == compare_value) {
    jint res = cmpxchg(new_val, dest_int, cur);
    if (res == cur) break;
    cur = res;
    new_val = cur;
    new_val_as_bytes[offset] = exchange_value;
  }
  return cur_as_bytes[offset];
}

CAS操作

通过内嵌汇编的方式通过对应的汇编指令执行CAS操作。

 

这里定义了一个宏LOCK_IF_MP:

 

#define LOCK_IF_MP(mp) "cmp $0, " #mp "; je 1f; lock; 1: "
 

 

CAS操作更新int类型

参考hotspot\src\os_cpu\linux_x86\vm\atomic_linux_x86.inline.hpp中的代码:

inline jint     Atomic::cmpxchg    (jint     exchange_value, volatile jint*     dest, jint     compare_value) {
  int mp = os::is_MP();
  __asm__ volatile (LOCK_IF_MP(%4) "cmpxchgl %1,(%3)"
                    : "=a" (exchange_value)
                    : "r" (exchange_value), "a" (compare_value), "r" (dest), "r" (mp)
                    : "cc", "memory");
  return exchange_value;
}

这里通过内嵌汇编的方式通过cmpxchgl汇编指令执行CAS操作。内嵌的汇编指令展开后:

 

__asm__ volatile ("cmp $0, " #%4 "; je 1f; lock; 1: " "cmpxchgl %1,(%3)"
                    : "=a" (exchange_value)
                    : "r" (exchange_value), "a" (compare_value), "r" (dest), "r" (mp)
                    : "cc", "memory");
 

 

 

CAS操作更新long类型

参考hotspot\src\os_cpu\linux_x86\vm\atomic_linux_x86.inline.hpp中的代码:

inline jlong    Atomic::cmpxchg    (jlong    exchange_value, volatile jlong*    dest, jlong    compare_value) {
  bool mp = os::is_MP();
  __asm__ __volatile__ (LOCK_IF_MP(%4) "cmpxchgq %1,(%3)"
                        : "=a" (exchange_value)
                        : "r" (exchange_value), "a" (compare_value), "r" (dest), "r" (mp)
                        : "cc", "memory");
  return exchange_value;
}

这里通过内嵌汇编的方式通过cmpxchgq汇编指令执行CAS操作。内嵌的汇编指令展开后:

 

__asm__ __volatile__ ("cmp $0, " #%4 "; je 1f; lock; 1: " "cmpxchgq %1,(%3)"
                        : "=a" (exchange_value)
                        : "r" (exchange_value), "a" (compare_value), "r" (dest), "r" (mp)
                        : "cc", "memory");
CAS操作更新oop类型,用于Java对象的CAS操作
参考hotspot\src\share\vm\oops\oop.inline.hpp中的代码:
inline oop oopDesc::atomic_compare_exchange_oop(oop exchange_value,
                                                volatile HeapWord *dest,
                                                oop compare_value) {
  if (UseCompressedOops) {
    // encode exchange and compare value from oop to T
    narrowOop val = encode_heap_oop(exchange_value);
    narrowOop cmp = encode_heap_oop(compare_value);

    narrowOop old = (narrowOop) Atomic::cmpxchg(val, (narrowOop*)dest, cmp);
    // decode old from T to oop
    return decode_heap_oop(old);
  } else {
    return (oop)Atomic::cmpxchg_ptr(exchange_value, (oop*)dest, compare_value);
  }
}
这里如果Compressed,调用Atomic::cmpxchg函数执行CAS操作,参考另一篇文章:https://lobin.iteye.com/blog/2327905,narrowOop其实就是个无符号int类型,所以这里调用的是针对int类型的CAS操作更新。否则调用Atomic::cmpxchg_ptr函数执行CAS操作。

 

CAS操作更新指针类型

 

有两个方法,一个是针对void*类型的,一个是针对intptr_t类型的。参考hotspot\src\os_cpu\linux_x86\vm\atomic_linux_x86.inline.hpp中的代码:

void*类型

inline void*    Atomic::cmpxchg_ptr(void*    exchange_value, volatile void*     dest, void*    compare_value) {
  return (void*)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value);
}

 

intptr_t类型

在hotspot\src\share\vm\utilities\globalDefinitions_gcc.hpp中,intptr_t定义如下:

 

// %%%% how to access definition of intptr_t portably in 5.5 onward?
typedef int                     intptr_t;
在hotspot\src\share\vm\utilities\globalDefinitions_sparcWorks.hpp中,intptr_t定义如下:

 

 

// %%%% how to access definition of intptr_t portably in 5.5 onward?
typedef int                     intptr_t;
在hotspot\src\share\vm\utilities\globalDefinitions_visCPP.hpp中,intptr_t定义如下:

 

如果定义了_WIN64宏

 

typedef signed   __int64 intptr_t;
否则

 

 

typedef signed   int intptr_t;
所以这里针对intptr_t类型的cmpxchg_ptr实际上是int类型,但这个int类型应该表示的是一个地址

 

inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value) {
  return (intptr_t)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value);
}

这两种类型调用还是针对long类型的CAS操作更新

 

1、https://docs.oracle.com/en/java

2、https://docs.oracle.com/javase/6/docs/

3、https://docs.oracle.com/en/java/javase/11/

分享到:
评论

相关推荐

    JAVA CAS实现原理与使用.docx

    在Java中,`java.util.concurrent.atomic`包下的原子类,如`AtomicInteger`,就是基于CAS实现的。 以`AtomicInteger`的`incrementAndGet()`方法为例,它用于实现无锁的自增操作。在循环中,线程首先获取当前值,...

    Java CAS 原理分析

    ### Java CAS 原理分析 #### 一、概述 CAS(Compare and Swap)作为一种重要的同步机制,在多线程环境中发挥着关键作用。它能够帮助开发者实现无锁编程,提高程序运行效率。本文将深入剖析Java中CAS的基本原理及其...

    JAVA CAS深度分析

    2. CAS 操作的实现:JAVA 中的 CAS 操作通过 sun.misc.Unsafe 类的 compareAndSwapInt() 方法实现,该方法借助 JNI 调用 CPU 底层指令来实现 CAS 操作。 3. CAS 操作的应用:JAVA 中的 CAS 操作主要应用于 java.util...

    cas java cas java 实例

    下面我们将详细探讨CAS的核心概念、工作原理以及如何在Java环境中实现和使用CAS。 1. CAS核心概念: - 服务(Service):在CAS术语中,服务是指请求验证的Web应用。当用户尝试访问受保护的资源时,会被重定向到CAS...

    Java CAS基本实现原理代码实例解析

    Java CAS基本实现原理代码实例解析 Java CAS(Compare And Swap,比较并交换)是 Java 中的一种并发机制,它可以实现原子性的操作。在 Java 中,CAS 是通过 java.util.concurrent.atomic 包来实现的,例如 ...

    Java并发机制的底层实现原理.pdf

    Java并发机制的底层实现原理涉及到多个方面,包括了本地内存与线程安全的问题、volatile关键字的使用、synchronized关键字的原理以及Java并发在处理器层面是如何实现的。通过这些机制,Java能够有效地管理多线程环境...

    java-cas单点登录服务端

    CAS(Central Authentication Service)是一款不错的针对 Web 应用的单点登录框架,本文介绍了 CAS 的原理、协议、在 Tomcat 中的配置和使用,研究如何采用 CAS 实现轻量级单点登录解决方案。 CAS 是 Yale 大学发起的...

    java-cas客户端client安装包

    Java CAS 客户端是Java应用程序与中央认证服务(CAS)进行交互的一种工具,它使得在分布式环境中实现单点登录(Single Sign-On, SSO)成为可能。CAS 是一个开源项目,由耶鲁大学发起,旨在提供一种安全的Web身份验证...

    CAS实现sso单点登录原理

    "CAS实现sso单点登录原理" CAS(Central Authentication Service)是Yale大学发起的一个企业级的、开源的项目,旨在为Web应用系统提供一种可靠的单点登录解决方法(属于Web SSO)。CAS开始于2001年,并在2004年12月...

    Java CAS底层实现原理实例详解

    "Java CAS底层实现原理实例详解" Java CAS(Compare And Swap)是一种机制,用于解决多线程并行情况下使用锁造成性能损耗的问题。CAS 的概念是,比较并交换,解决多线程并行情况下使用锁造成性能损耗的一种机制。...

    深入探索Java中的CAS操作:原理、实现与应用

    本文将详细介绍CAS的工作原理、实现方式以及在Java中的应用。 CAS操作是Java并发编程中的一项重要技术,它通过无锁的方式提供了线程安全的数据操作。通过理解CAS的工作原理和底层实现,我们可以更有效地使用Java中的...

    sso/cas单点登录Java maven版 含服务端客服端

    总的来说,这个项目提供了Java环境下使用Maven构建的CAS SSO解决方案,可以帮助开发者快速搭建一套SSO环境,实现不同应用间的统一登录管理。通过理解服务端和客户端的工作原理以及配置方法,可以灵活地适应各种应用...

    cas4.2.7 实现其他系统和cas互相认证互信

    3. **集成CAS客户端库**:在外部系统中,需要集成CAS客户端库,如Java CAS Client、Spring Security CAS等,它们负责处理与CAS服务器的交互,包括重定向用户到CAS登录页面、接收和验证服务票证。 4. **配置客户端...

    java LDAP+CAS单点登录

    4. **程序源码**:可能包括了一个示例项目,展示了完整的Java LDAP+CAS集成的实现。 5. **群组信息**:提供了一个讨论组的联系方式,供用户交流和寻求帮助。 通过理解和实施这些资源,你可以学习到如何在Java环境中...

    CAS集成手册(java版

    对于Java开发者来说,理解和掌握这些组件的工作原理以及如何配置和使用它们,是成功集成CAS的关键。在实际应用中,还应关注性能优化,如调整缓存策略,减少网络延迟,以达到"提速N倍"的效果。此外,由于CAS支持多种...

    CAS原理和配置过程

    ### CAS原理详解 CAS(Central Authentication Service)是一种开放源代码的单点登录协议和服务实现,广泛应用于企业级应用系统中。其主要目的是提供一个统一的身份验证解决方案,使得用户只需要在一个地方进行登录...

    Java进阶SSO单点登录技术CAS-快速上手与原理探究视频教程

    本课程主要通过CAS来实现SSO,本教程会从最基本的基础知识讲起,由浅入深再到实战,完成多应用的单点登录功能。 本课程内容如下: 1、 什么是SSO和CAS 2、 CAS Server服务端和客户端的搭建和配置 3、 单点登录和单...

    Yale CAS SSO JAVA Client

    整合Yale CAS SSO JAVA Client到Java应用中,开发者需要理解CAS的工作原理,包括Ticket Granting Ticket(TGT)和Service Ticket的概念,以及如何在应用程序中配置和调用CAS客户端库。同时,为了保证安全性,需要...

Global site tag (gtag.js) - Google Analytics