java虚拟机 (8)

2)如果在类型C中找到与常量中的描述符和简单名称都相符的方法,则进行访问权限校验,如果 通过则返回这个方法的直接引用,查找过程结束;不通过则返回java.lang.IllegalAccessError异常。

3)否则,按照继承关系从下往上依次对C的各个父类进行第二步的搜索和验证过程。

4)如果始终没有找到合适的方法,则抛出java.lang.AbstractMethodError异常。

单分派与多分派

方法的接收者与方法的参数统称为方法的宗量。根据分派基于多少种宗量,可以将分派划分为单分派和多分派两种。单分派是根据一个宗量对 目标方法进行选择,多分派则是根据多于一个宗量对目标方法进行选择。我看起来就是重载加重写的数量有多个。当父类出现重载,子类继承并重写,那么进行方法调用的时候根据目标方法的依据有两种,静态类型是父类还是子类,方法参数是不同重载方法的哪个,两个宗量进行选择,所以是静态分派多分派。而动态分派的时候已经确定了重载的目标方法是哪个,只需要关注实际接受者是父类还是子类,那么这个宗量选择就只有一个就称为单分派。

动态类型语言支持

Java虚拟机的字节码指令集的数量自从Sun公司的第一款Java虚拟机问世至今,二十余年间只新增 过一条指令,它就是随着JDK 7的发布的字节码首位新成员——invokedynamic指令。

动态类型语言

动态类型语言的关键特征是它的类型检查的主体过程是在运行期而不是编译期进行的

JDK 7时新加入的java.lang.invoke包[1]是JSR 292的一个重要组成部分,这个包的主要目的是在之前 单纯依靠符号引用来确定调用的目标方法这条路之外,提供一种新的动态确定目标方法的机制,称 为“方法句柄”(Method Handle)

确实,仅站在Java语言的角度看,M ethodHandle在使用方法和效果上与Reflection有众多相似之 处。不过,它们也有以下这些区别:

Reflection和M ethodHandle机制本质上都是在模拟方法调用,但是Reflection是在模拟Java代码层次 的方法调用,而M ethodHandle是在模拟字节码层次的方法调用。在M ethodHandles.Lookup上的3个方法 findStatic( ) 、 findVirtual( ) 、 findSpecial( ) 正是为了对应于invokestatic、invokevirtual( 以 及 invokeinterface)和invokesp ecial这几条字节码指令的执行权限校验行为,而这些底层细节在使用 Reflection API时是不需要关心的。

Reflection中的java.lang.reflect.M ethod对象远比MethodHandle机制中的
java.lang.invoke.MethodHandle对象所包含的信息来得多。前者是方法在Java端的全面映像,包含了方法 的签名、描述符以及方法属性表中各种属性的Java端表示方式,还包含执行权限等的运行期信息。而 后者仅包含执行该方法的相关信息。用开发人员通俗的话来讲,Reflection是重量级,而M ethodHandle 是轻量级。

由于MethodHandle是对字节码的方法指令调用的模拟,那理论上虚拟机在这方面做的各种优化 (如方法内联),在MethodHandle上也应当可以采用类似思路去支持(但目前实现还在继续完善 中),而通过反射去调用方法则几乎不可能直接去实施各类调用点优化措施。

MethodHandle与Reflection除了上面列举的区别外,最关键的一点还在于去掉前面讨论施加的前提“仅站在Java语言的角度看”之后:Reflection API的设计目标是只为Java语言服务的,而MethodHandle 则设计为可服务于所有Java虚拟机之上的语言,其中也包括了Java语言而已,而且Java在这里并不是主角。

JAVA内存模型与线程

基于高速缓存的存储交互很好地解决了处理器与内存速度之间的矛盾,但是也为计算机系统带来 更高的复杂度,它引入了一个新的问题:缓存一致性(Cache Coherence)。在多路处理器系统中,每 个处理器都有自己的高速缓存,而它们又共享同一主内存(Main Memory),这种系统称为共享内存 多核系统(Shared Memory Multiprocessors System)。“内存模型”,在特定的操作协议下,对特定的内存或高速缓存进行读写访问的过程抽象。不同架构的物理机器可 以拥有不一样的内存模型,而Java虚拟机也有自己的内存模型。

JAV内存模型 主内存和工作内存

Java内存模型的主要目的是定义程序中各种变量的访问规则,即关注在虚拟机中把变量值存储到 内存和从内存中取出变量值这样的底层细节。Java内存模型规定了所有的变量都存储在主内存中(此处的主内存与物理硬件时提到的主内存可以类比,但物理上它仅是虚拟机内存的一部分)。每条线程还有自己的工作内存(可与处理器高速缓存类比),线程的工作内存中保存了被该线程使用的变量的主内存副本[2],线程对变量的所有操作(读取、赋值等)都必须在工作内存中进行,而不能直接读写主内存中的数据[3]。不同的线程之间也无法直接访问对方工作内存中的变 量,线程间变量值的传递均需要通过主内存来完成

内存间交互操作

lock(锁定):作用于主内存的变量,它把一个变量标识为一条线程独占的状态。

unlock(解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量 才可以被其他线程锁定。

read(读取):作用于主内存的变量,它把一个变量的值从主内存传输到线程的工作内存中,以 便随后的load动作使用。

load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的 变量副本中。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpwgdz.html