javacore分析
java程序运行时,有时会产生javacore及heapdump文件,java程序在遇到致命问题时,就会产生这两个文件,有时产生时,java应用不会死掉,还能继续运行,有时则java进程会死掉,即java进程被杀死。
为了能够保留java应用发生致命错误前的java的运行状态,jvm 在死掉前产生两个文件,分别为javacore及heapdump文件。
javacore文件主要保存的是java应用各线程在某一时刻的运行的位置,即执行到哪一个类的哪一个方法哪一个行上。
javacore是一个文本文件,打开后可以看到每一个线程的执行栈,以stacktrace的方式显示。
通过对javacore的分析可以得到应用是否“卡”在某一点上,即在某一点运行的时间太长,如数据库查询,长期得不到响应,最终导致系统崩溃。
heapdump文件是一个二进制文件,它保存了某一时刻jvm堆中对象情况,这种文件需要相应的工具进行分析,笔者用得较多的是heap analyzer这个工具。
这个文件最重要的作用就是分析系统是否存在内存溢出的情况,通过heapanalyzer可以很简单地分析出溢出的位置。
这两个文件也可以手工的方式生成,经常我们会遇到系统变慢或无响应的情况,这个时候就以采用手工的方式生成javacore及heapdump文件,通过对这两个文件的分析,查出原因进而解决问题,在unix/linux上,产生这两个文件的方法是首先,ps -ef|grep java 找出java 进程id ,然后再执行kill -3 进程号的操作,等文件生成后再做一次同样的操作,再产生一组文件,两组文件在分析javacore时特别有效,困为它可以看出在先后两个时间点上,线程执行的位置,如果发现先后两组数据中同一线程都执行在同一位置,则说明此处可能有问题,因为程序运行是极快的,如果两次均在某一点上,说明这一点耗时是很大的。
1.Java DUMP分析Java dump 文件的格式和内容Java dump 通常是文本格式(.txt),因此可以通过一般的文本编辑器进行阅读,阅读时需要注意段与行的格式:段格式为了便于大家的分析,Java dump 的每一段的开头,都会用“-----”与上一段明显的区分开来。
而每一段的标题也会用“=====”作为标识,这样我们就能够很容易的找到每一段的开头和标题部分(如清单1)。
行格式Java dump 文件中,每一行都包含一个标签,这个标签最多由15 个字符组成(如清单2中所示)。
其中第一位数字代表信息的详细级别(0,1,2,3,4),级别越高代表信息越详细;接下来的两个字符是段标题的缩写,比如,“CI” 代表“Command-line interpreter”,“CL” 代表“Class loader”,“LK” 代表“Locking”,“ST” 代表“Storage”,“TI” 代表“Title”,“XE” 代表“Execution engine”等等;其余部分为信息的概述。
清单2. Java dump 行标签和内容示例不同版本的JVM 所产生的Java dump 的格式可能会稍有不同,但基本上都会包含以下几个方面的内容:∙TITLE 信息块:描述JAVA DUMP 产生的原因,时间以及文件的路径。
∙GPINFO信息块:GPF 信息。
∙ENVINFO 信息块:系统运行时的环境及JVM 启动参数。
∙MEMINFO 信息块:内存的使用情况和垃圾回收记录。
∙LOCKS 信息块:用户监视器(Monitor)和系统监视器(Monitor)。
∙THREADS信息块:所有java 线程的状态信息和执行堆栈。
∙CLASSES信息块:类加载信息。
回页首利用Java Dump 进行JVM 故障诊断由于Java dump 文件包含的内容比较广泛,因此JVM 的很多问题都可以通过java dump进行诊断。
这些问题主要包括线程阻塞,CPU 使用率过高,JVM Crash,堆内存不足,和类装载等问题。
诊断线程阻塞问题线程阻塞是我们在java 多线程编程中经常遇到的问题。
由于对后端有限资源的争用以及过度同步等问题,经常会发现Java dump 中某个资源(锁对象)下有太多的线程处于等待状态,这时候我们通常需要从以下三个方面去诊断这个问题:∙这个锁存在的目的是什么?有没有可能去掉这个锁或者缩小这个锁保护的范围,从而减少线程等待问题发生的几率。
∙有哪些线程需要用到这个锁,有没有可能改用其它更好的替代方案。
∙当前哪个线程正在持有这个锁,持有的时间是多长,有没有可能缩短持有的时间。
比线程阻塞更严重的是死锁问题,当两个以上的线程互相等待对方的锁,从而形成一个环的时候,就会发生死锁。
关于如何使用Java dump 诊断死锁的问题,请参考在WebSphere Application Server V6.1 应用程序中跟踪死锁一文,该文对此问题做了较为详细的介绍。
诊断JVM Crash 问题JVM Crash 是我们所碰到的最棘手的问题之一,它对整个系统的影响是致命的,并且总是让人防不胜防。
导致JVM 崩溃的原因有很多,通常都是一些底层的错误。
比如JVM 本身的bug,错误的JNI 调用,第三方原生模块(比如数据库驱动程序)中的bug 等。
JVM崩溃的原因复杂,并且大多都难以重现,所以诊断起来有一定的难度。
一般来说,JVM 崩溃的时候,系统一般会自动产生一个Java dump 文件(JVM 默认的设置参数就会触发)。
这个Java dump 会帮我们记录下JVM 崩溃的原因,相关的信息会记录在TITLE 信息块,GPINFO 信息块和THREADS 信息块中。
∙TITLE 信息块:用于确认问题产生的原因,即是否是由于一些底层错误而导致JVM Crash。
∙GPINFO 信息块:用于查看问题的详细信息和问题定位。
∙THREADS信息块:用于了解问题线程的运行情况。
下面我们通过一个具体的例子来介绍JVM Crash 问题的诊断方法。
TestJni 是一个简单的Java 应用,它通过JNI 调用本地代码CallJin.dll 中的doSomeThing() 函数。
清单3. 在TestJni 类中调用CallJin.dll 中的函数CallJin.dll 是C++ 编写得本地库,其源代码如清单3 所示:在这段C++ 代码中,整形指针I 还没有分配空间就被赋了值,这是一个非常严重的错误。
当然java 应用程序员并不知道这一点,并且在java 应用程序中调用了doSomeThing()这个JNI 函数。
结果导致JVM 发生了崩溃。
在这段C++ 代码中,整形指针I 还没有分配空间就被赋了值,这是一个非常严重的错误。
当然java 应用程序员并不知道这一点,并且在java 应用程序中调用了doSomeThing()这个JNI 函数。
结果导致JVM 发生了崩溃。
下面是JVM 崩溃时,系统为我们生成的Java dump 文件的片断。
从TITLE 信息块中我们可以看到,这个java 是由一个"gpf" 事件触发的,GPF 是General Protection Fault 的缩写,表明应用程序发生了一般性保护错误,这种错误常常导致JVM 突然崩溃。
除了"gpf" 之外,Java dump 还可能由如下事件触发(清单6)。
从TITLE 信息块,我们只能初步了解问题产生的原因,如果要进一步了解问题的详细信息,还要查看GPINFO 信息块(清单7):GPINFO 信息块中我们可以找到问题的异常代码,ExceptionCode: C0000005代表内存访问错误或者非法的内存操作。
Module:C:\eclipse\workspace\Serviceability\TestApps\TestJin\Call Jni.dll指明了发生问题的原生模块。
CallJni.dll 这个动态连接库是我们自己的JNI 代码,因此很容易发现问题的所在。
在一个复杂的java 运行环境下,很多时候异常是在第三方的代码库中产生的,我们没有办法查看源代码中的问题,这时候只能通过文件名中的一些关键字来推测问题发生的位置,这些关键字包括(清单8):例如,Module: C:\JDK\IBM\java1.5.0\jre\bin\j9jit23.dll说明JIT 模块发生问题,用户可以使用JITC_COMPILEOPT 变量的SKIP 选项禁用对当前方法进行JIT 编译,然后再对系统的运行情况进行进一步的跟踪。
JITC_COMPILEOPT=SKIP{failingPackage/failingClass}{failing Method}除此之外,查看THREADS 信息块中当前线程的执行堆栈也有助于我们对问题的诊断。
从清单9 我们可以看到main 线程在执行CallJni.doSomeThing 方法数的过程中发生了问题,据此我们可以返回源代码中查找相应的方法,进而确定问题的根源。
诊断CPU 利用率过高问题CPU 使用率过高可能是由于某些线程陷入了死循环或者执行了不适当的操作引起的,其诊断方法就是将这些线程找出来,修正问题或者进行代码优化。
由于Java Dump 中并没有包含各线程的资源使用情况,因此我们需要结合其他的操作系统命令/工具(prstat、top、pslist 等等),将CPU 使用率较高的线程映射到Java Dump 中,并分析这些线程的状态以及可能发生的问题。
从下面这段PSList 的输出结果中我们可以看到jvm 内部每个线程消耗的总的“用户时间”和“内核时间”,比较几次PSList 的输出结果,我们就能从中找出那些CPU 使用时间显著增加的线程,再将这些线程的TID 映射到Java Dump中,进而查看问题线程的详细信息。
与线程死锁问题不同,在分析CPU 利用率过高的问题时,我们不需要关心那些处于等待状态的线程,因为线程处于等待状态不需要消耗CPU 资源。
我们关注的重点应该是THREADS 信息块中那些正在运行(state:R 状态)的线程。
很多时候为了分析线程状态的一些变化,我们需要对比多个Java Dump 文件,看哪些线程状态发生了变化,哪些一直在执行相同的函数,从而找出那些可疑的问题线程。
诊断堆内存不足问题除了Thread 相关的信息外,Java Dump 还包含Memory 和GC 等方面的信息,虽然这些信息不像Heap Dump 和VerboseGC 那么详细,但对于一些比较简单的问题定位还是很有帮助的。
例如,下面的Java dump 清单中,Dump Event "uncaught" (00008000) Detail"java/lang/OutOfMemoryError" received告诉我们问题是由于内存溢出引起的,并且从MEMINFO 信息块中可以找到当前堆中的空间使用情况,1ffa0 的剩余空间说明系统的可用堆内存已经严重不足了,需要我们扩大堆内存的大小或者修改应用程序使其占用更少的内存。
基于Java的智能问答系统设计与实现
基于Java的智能问答系统设计与实现智能问答系统是一种能够理解自然语言并给出准确答案的人工智能系统。
随着人工智能技术的不断发展,智能问答系统在各个领域得到了广泛的应用,如智能客服、智能助手等。
本文将介绍基于Java语言的智能问答系统的设计与实现过程。
1. 智能问答系统概述智能问答系统是一种基于自然语言处理和人工智能技术的应用系统,其核心功能是接受用户提出的问题,并给出相应的答案。
智能问答系统通常包括问题理解、知识检索和答案生成三个主要模块。
在本文中,我们将使用Java语言来实现一个简单的智能问答系统。
2. 技术选型在设计智能问答系统时,我们需要选择合适的技术栈来支撑系统的实现。
考虑到Java语言在企业级应用开发中的稳定性和可靠性,我们决定采用Java作为主要开发语言。
此外,我们还将使用以下技术来构建系统:Spring框架:用于构建系统的后端服务,提供依赖注入和面向切面编程等功能。
Elasticsearch:用于存储和检索知识库中的问题和答案。
Stanford CoreNLP:用于自然语言处理,包括分词、词性标注、句法分析等功能。
3. 系统架构设计基于以上技术选型,我们设计了如下的智能问答系统架构:前端界面:用户通过前端界面输入问题,并展示系统返回的答案。
后端服务:包括问题理解、知识检索和答案生成三个模块。
问题理解:利用自然语言处理技术对用户输入的问题进行分析和理解。
知识检索:通过Elasticsearch从知识库中检索相关问题和答案。
答案生成:根据检索结果生成最终的回答,并返回给用户。
知识库:存储系统所需的问题和对应的答案,以便后续检索和生成。
4. 系统实现步骤4.1 数据准备首先,我们需要准备一个包含问题和答案对的知识库。
可以手动录入一些常见问题和标准答案,也可以通过爬虫等方式从互联网上获取数据。
将这些数据存储在Elasticsearch中以便后续检索。
4.2 问题理解模块问题理解模块是整个系统的核心部分,它需要对用户输入的问题进行分词、词性标注、句法分析等处理,以便后续进行知识检索。
数据库安装升级出错案例2
2.更换oracle安装介质以后,仍然不成功
3.在备机上卸载oracle,重新安装oracle 11.1.0.6.0也报同样错误
4.检查参数设置后发现maxuproc=2048,这个参数是允许用户处理的最大进程数,查看安装指南发现这个参数应该设置为16384。
附件:
2
现象描述:
OS平台:AIX5.3
数据库版本:ORACLE 11.1GHA
升级11.1.0.7.0 runInstaller时异常
告警信息:
lsnls11 -lnls11 -lcore11 -lnls11 -lld -lm `cat /home/oracle/db/lib32/sysliblist` -lm -lpls11 -lrt -lsql11 `if [ "\`/usr/bin/uname -v\`" = "4" ]; \
then echo "-bI:/home/oracle/db/lib/pw-syscall.exp"; fi;`
ld: 0711-715 ERROR: File /home/oracle/db/lib32/stubs//librt.so cannot be processed.
The file must be an object file, an import file, or an archive.
make: The error code from the last command is 8.
原因分析:
Maxuproc参数设置太小,导致安装11.1.0.6.0时就有问题
处理过程:
java多线程实验报告
java多线程实验报告一、实验目的本次实验旨在探究Java多线程编程的原理和技巧,以及如何应用多线程编写高效、稳定、可靠的多线程应用程序。
二、实验环境本次实验使用的环境为:硬件:Intel Core i5 2.5 GHz处理器,8GB内存,256GB SSD硬盘软件:Windows 10操作系统,JDK 1.8开发工具三、实验步骤1. 编写并运行多线程程序2. 对程序进行分析、调试和优化3. 测试程序的效率和稳定性4. 记录实验过程和实验结果5. 撰写实验报告四、实验过程1. 编写并运行多线程程序本次实验编写的多线程程序是一个简单的计时器,程序的主要功能是在控制台上输出1-100的数字,并在输出每一个数字之前暂停一段时间,以模拟实际应用中的处理等待。
具体代码如下:public class MyThread extends Thread {private int delay;private int count;public MyThread(int delay, int count) {this.delay = delay;this.count = count;}@Overridepublic void run() {for (int i = 1; i <= count; i++) {try {Thread.sleep(delay);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(i);}}}public class Main {public static void main(String[] args) {MyThread thread1 = new MyThread(100, 100); MyThread thread2 = new MyThread(50, 100); thread1.start();thread2.start();}}2. 对程序进行分析、调试和优化在程序分析、调试和优化的过程中,我遇到了以下几个问题和解决方法:问题1:程序多次运行时,会出现线程执行顺序不同的情况;解决方法:使用Thread.sleep和yield方法来控制线程执行顺序。
allowcorethreadtimeout参数说明
allowcorethreadtimeout参数说明在Java的多线程开发中,默认情况下Java虚拟机并不会完全杀死空闲的线程。
这就可能导致程序运行时间过长,使用过多的资源,对系统造成不必要的负担,因此Java提供了一种参数——allowCoreThreadTimeout,用于指定是否允许核心线程空闲超时。
allowCoreThreadTimeout的默认值为false,即核心线程永远不会被杀死,这意味着如果线程池中某个线程不能完全处理完它的任务,那么这个线程将一直保持活动状态,甚至在没有任务可以处理的情况下,它也会一直保持活动状态,并且会占用CPU资源。
在某些情况下,我们需要开启allowCoreThreadTimeout参数。
如果设置为true,那么当线程池中的线程数大于核心线程数时,非核心线程空闲时间超过了指定时间就会被杀死。
下面通过几个步骤来详细介绍如何在Java中设置allowCoreThreadTimeout参数。
第一步是创建线程池。
我们可以使用Java中java.util.concurrent包的ThreadPoolExecutor类来实现线程池功能。
这里我们创建一个包含4个线程的线程池,其中2个是核心线程:\lstset{language=java,numbers=none}\begin{lstlisting}ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<>(2));\end{lstlisting}第二步是设置allowCoreThreadTimeout参数。
我们可以通过使用ThreadPoolExecutor类的setKeepAliveTime方法和allowCoreThreadTimeout参数来进行设置。
java面试的自我介绍(精彩6篇)
java面试的自我介绍(精彩6篇)(经典版)编制人:__________________审核人:__________________审批人:__________________编制单位:__________________编制时间:____年____月____日序言下载提示:该文档是本店铺精心编制而成的,希望大家下载后,能够帮助大家解决实际问题。
文档下载后可定制修改,请根据实际需要进行调整和使用,谢谢!并且,本店铺为大家提供各种类型的经典范文,如总结报告、心得体会、应急预案、演讲致辞、合同协议、规章制度、条据文书、教学资料、作文大全、其他范文等等,想了解不同范文格式和写法,敬请关注!Download tips: This document is carefully compiled by this editor. I hope that after you download it, it can help you solve practical problems. The document can be customized and modified after downloading, please adjust and use it according to actual needs, thank you!Moreover, our store provides various types of classic sample essays, such as summary reports, insights, emergency plans, speeches, contract agreements, rules and regulations, documents, teaching materials, complete essays, and other sample essays. If you would like to learn about different sample formats and writing methods, please pay attention!java面试的自我介绍(精彩6篇)java面试的自我介绍篇一各位领导好,我叫,剩余的余,金子的金。
第2章_Java基本数据和运算
5 % 2= 1 5/2=2
分析运行结果
public class OperatorTest { public static void main(String[] args) { int i =7/3; int j =2+7%i; double k = 7.8/i+5; System.out.println("i="+i); System.out.println("j="+j); System.out.println(”k="+k); } }
算术运算符应用
某学生有3门课成绩,编程实现求平均分。
public class Test1 { public static void main(String[ ] args) { String name= "刘星"; //姓名 int javaScore=90; //Java成绩 int webScore=86; // Web成绩 int sqlScore=88; //Sql 成绩 double avgScore; //平均成绩 avgScore= (webScore+javaScore+sqlScore)/3; System.out.println("学生姓名:"+name); System.out.println("平均成绩:"+avgScore); } }
?
常见错误
下面语句正确吗?
int a = 10; int b = 10.2; double c = 10; c = a; int d = c; double不可以自动转化成int
分析运行结果
public class TypeTest1 { public static void main(String[] args) { int a = 5; float x = a; //自动类型转换 double y= 5.8; int b=(int)y; //强制类型转换 System.out.println("a="+a); System.out.println("x="+x); System.out.println("y="+y); System.out.println("b="+b); } }
newscheduledthreadpool corepolesize
newscheduledthreadpool corepolesize本文将围绕Java中的线程池常用参数“newScheduledThreadPool corePoolSize”进行阐述。
线程池是一种常见的多线程编程技术,通过重用已有线程来减少创建新线程的开销,从而提高程序执行效率。
具体将从以下几个方面进行讲解:1. 线程池简介2. newScheduledThreadPool的作用及使用3. corePoolSize参数的理解4. 实例演示一、线程池简介线程池是Java多线程编程中常用的一种技术,Java语言提供了3种线程池:FixedThreadPool、CachedThreadPool和ScheduledThreadPool。
线程池中包含若干个线程,用于执行多个任务。
当有任务到达时,线程池会从线程池中选取一个可用线程执行任务,如果没有可用线程,则等待直到有空闲线程。
线程池的好处在于可以重复利用线程,减少线程创建和销毁的开销,提高程序性能,同时避免了线程数量过多导致程序崩溃的问题。
二、newScheduledThreadPool的作用及使用newScheduledThreadPool是Java提供的一种ScheduledThreadPoolExecutor类型的线程池。
ScheduledThreadPoolExecutor是一个大小可调的线程池,可以延迟或定时执行任务。
newScheduledThreadPool可以根据需要创建新线程,并通过参数进行控制线程池的大小和时间。
使用newScheduledThreadPool可以更好地控制和执行一些需要定时触发的任务。
3. corePoolSize参数的理解newScheduledThreadPool中的corePoolSize参数是控制线程池中的核心线程数量的参数。
核心线程是指在线程池中一直存在的线程,在线程池有足够任务需要执行时,核心线程会一直存在。
一次OOM排查过程
⼀次OOM排查过程⼀、外在表现前段时间系统经常出现OOM,服务很不稳定,偶尔会有java进程不存在的情况,临时解决⽅案只能是重启。
⼆、辅助⼯具1.top⽤top查看,发现内存占⽤(%MEM)挺多,其他指标均正常。
2.dmesg如果发现⾃⼰的java进程突然消失了,那么就要借助dmesg来查看开机之后的系统⽇志命令为dmesg | grep -i 'kill'或者搜索oom(out of memory),如果能搜索到相关信息,则说明java进程是被操作系统kill了,操作系统有⼀种机制,它会在机器的内存耗尽前,挑选⼏个占⽤内存较⼤的进程杀死(实际也是有⼀定的计算规则),通常被杀死的就是java进程,那么接下来就是看看是什么原因造成内存这么⼤。
dmesg 输出的格式不易查看,可以通过命令进⾏转换。
date -d "1970-01-01 UTC `echo "$(date +%s)-$(cat /proc/uptime|cut -f 1 -d' ')+12288812.926194"|bc ` seconds"三、排查过程OOM的原因⼀般为内存泄露,创建了对象不能释放,也有可能是突然间创建了⼤对象,有时加载过多的class也是原因。
线上遇到OOM需要做两件事情第⼀个是dump内存,第⼆个是看下GC⽇志。
1. jps -mlvV (或者 ps -ef | grep java)找出当前java进程号1234linux环境下可能要先执⾏export JAVA_HOME=/*/*export PATH=$JAVA_HOME/bin:$PATH2. jstat -gcutil 1234 1000 10从这⼀步查出,full gc次数频繁,由此可见原因是⽼年代空间不⾜3. dump内存接下来就是排查问题最重要的⼀步,dump内存最容易想到的是jmap -dump:format=b,file=heap.hprof 1234。
java中的connectionreset异常处理分析
java中的connectionreset异常处理分析在Java中常看见的⼏个connection rest exception, Broken pipe, Connection reset,Connection reset by peerSocked reset caseLinux中会有2个常见的sock reset 情况下的错误代码ECONNRESET该错误被描述为“connection reset by peer”,即“对⽅复位连接”,这种情况⼀般发⽣在服务进程较客户进程提前终⽌。
当服务进程终⽌时会向客户 TCP 发送 FIN 分节,客户 TCP 回应 ACK,服务 TCP 将转⼊ FIN_WAIT2 状态。
此时如果客户进程没有处理该 FIN (如阻塞在其它调⽤上⽽没有关闭 Socket 时),则客户 TCP 将处于 CLOSE_WAIT 状态。
当客户进程再次向FIN_WAIT2 状态的服务 TCP 发送数据时,则服务 TCP 将⽴刻响应 RST。
⼀般来说,这种情况还可以会引发另外的应⽤程序异常,客户进程在发送完数据后,往往会等待从⽹络IO接收数据,很典型的如 read 或 readline 调⽤,此时由于执⾏时序的原因,如果该调⽤发⽣在 RST 分节收到前执⾏的话,那么结果是客户进程会得到⼀个⾮预期的 EOF 错误。
此时⼀般会输出“server terminated prematurely”-“服务器过早终⽌”错误。
EPIPE错误被描述为“broken pipe”,即“管道破裂”,这种情况⼀般发⽣在客户进程不理会(或未及时处理)Socket 错误,继续向服务TCP 写⼊更多数据时,内核将向客户进程发送 SIGPIPE 信号,该信号默认会使进程终⽌(此时该前台进程未进⾏ core dump)。
结合上边的 ECONNRESET 错误可知,向⼀个 FIN_WAIT2 状态的服务 TCP(已 ACK 响应 FIN 分节)写⼊数据不成问题,但是写⼀个已接收了 RST 的 Socket 则是⼀个错误。
javaAtomiccompareAndSet部分原理分析
javaAtomiccompareAndSet部分原理分析以AtomicLong的compareAndSet⽅法举例。
先说结论:如果CPU⽀持,则基于CPU指令(CMPXCHG8)实现;否则使⽤ObjectLocker锁实现。
分析过程如下:该⽅法在jdk中源代码如下:public final boolean compareAndSet(long expect, long update) {return pareAndSwapLong(this, valueOffset, expect, update);}unsafe是sun.misc.Unsafe的⼀个实例,Unsafe类在jdk中没有源代码,是由jvm提供的native代码。
在openjdk中对应位置是hotspot/src/share/vm/prims/unsafe.cppjdk代码⾥没有⽤锁,对⽤户来说是⽆锁的操作openjdk⾥是怎么实现pareAndSwapLong的呢?直接⽤代码说话,如下: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可以看到,如果不⽀持cx8,那么就需要⽤到ObjectLocker锁,那么什么 VM_Version::supports_cx8() 的底层实现⼜是什么呢?还是上代码,在openjdk/hotspot/src/share/vm/runtime/vm_version.hpp⾥static bool supports_cx8() {#ifdef SUPPORTS_NATIVE_CX8return true;#elsereturn _supports_cx8;#endif}_supports_cx8在何处赋值呢?该值默认为false,在x86系统中使⽤supports_cmpxchg8()⽅法赋值,在sparc系统中使⽤has_v9()赋值。
