资讯专栏INFORMATION COLUMN

Java 虚拟机总结给面试的你(下)

amc / 3377人阅读

摘要:本篇博客主要针对虚拟机的晚期编译优化,内存模型与线程,线程安全与锁优化进行总结,其余部分总结请点击虚拟总结上篇,虚拟机总结中篇。

本篇博客主要针对Java虚拟机的晚期编译优化,Java内存模型与线程,线程安全与锁优化进行总结,其余部分总结请点击Java虚拟总结上篇 ,Java虚拟机总结中篇。

一.晚期运行期优化 即时编译器JIT

即时编译器JIT的作用就是热点代码转换为平台相关的机器码,并进行优化,它并不是一个虚拟机所必须的部分,只能说有它是锦上添花。

热点代码 热点代码分类

被多次调用的方法

被多次调用的循环体

热点探测判定方法

基于采样的热点探测,虚拟机周期性地检查栈顶,发现某个方法经常出现在栈顶,那么这个方法就是热点方法,简单高效但不精确

基于计数器热点探测,为每个方法建立计数器来统计执行次数,超过阈值就是热点方法,Hotpot就是采用这种方法。分为方法计数器(统计方法),回边计数器(统计循环)

编译过程(Client Complier)

第一阶段

将字节码构造成高级中间代码表示(HIR)

第二阶段

将HIR变为LIR

第三阶段

使用线性扫描算法,在LIR上分配寄存器,产生机器代码

优化方法 公共子表达式优化

当一个表达式A的结果已经计算过了,且A中的所有变量都没有发生过变化,那么下一次要用到A时就不用计算了,而是直接取之前A的结果。

数组边界检查消除 方法内联 逃逸分析

逃逸的定义:一个在方法里定义的变量,作为参数传递给其他方法(方法逃逸),或者赋值给类变量(线程逃逸)。

优化方法:

栈上分配:不会逃逸的对象就不在堆上分配了,就在栈上分配,那么对象所占的空间就可以随栈帧的出栈而销毁,减少垃圾收集系统的压力。

同步消除:如果一个变量肯定不会逃逸出线程,那么关于这个变量的同步措施就可以去掉。

二.Java内存模型与线程 内存模型

说了这么多的内存模型,到底什么是内存模型呢?

特定的操作协议下,对特定的内存或高速缓存进行读写访问的过程抽象。

它的作用是定义程序中各个共享的变量的访问规则,即如何将变量写入内存和从内存中取出变量。Java内存模型有主内存与工作内存之分,所有变量存在主内存中,线程则是拥有自己的工作内存,它是主内存的副本拷贝,线程只能读写工作内存。

8种原子操作

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

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

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

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

use(使用):作用于工作内存的变量,它把工作内存中一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的值的字节码指令时将会执行这个操作。

assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。

store(存储):作用于工作内存的变量,它把工作内存中一个变量的值传送到主内存中,以便随后的 write 操作使用。

write(写入):作用于主内存的变量,它把 store 操作从工作内存中得到的变量的值放入主内存的变量中。

volatile变量的特殊规则

volatile的特性是保证此变量对所有线程的可见性,即当变量的值修改后,其他线程可以立即知道发生的变化。普通变量则是修改完值后,需要写回主内存,然后其他线程再从主内存读取该数据。volatile还可以通过内存屏障来禁止指令的重排序。综合来讲它的读操作和普通变量差不多,写操作慢一点。

long和double变量的特殊规则

8种操作一般都是原子性的,但是对于64位的数据,内存模型允许将没有被volatile修饰的64位数据的读写操作划分为两次32位的操作进行---->非原子协定但一般我们不需要将long和double声明为volatile。

先行发生原则

程序次序规则

管程锁定规则

volatile变量规则

线程启动规则

线程终止规则

线程中断规则

对象终结规则

传递性

Java与线程

Java的Thread类大多API都是Native方法,是与平台相关的。

实现线程的三种方式

使用内核线程实现:内核线程即直接由操作系统内核支持的线程,由内核来完成线程切换,程序使用轻量级进程接口与内核线程一对一的关系,内核线程再经由线程调度器分派给CPU。

使用用户线程实现:用户线程的建立同步销毁调度完全在用户态中完成,不需切换到内核态,一对多的关系。

用户线程+轻量级进程:多对多的关系。

线程的调度

协同式调度

线程的执行时间由线程自己控制,执行完后再主动通知系统切换线程,可能会导致一个线程长时间地阻塞

抢占式调度

由系统分配时间,线程可以主动让出时间但是不能主动获得时间,通过设置优先级确定顺序

线程的状态

新建:刚刚创建还未启动

运行:正在执行或者等待分配时间

无限等待:不会被CPU分配时间,需要其他线程显式唤醒

有限等待:在一段时间后由系统自动唤醒

阻塞:等待一个排他锁

结束

三.线程安全与锁优化 线程安全的程度,依次减弱

不可变,将对象中带状态的变量都置为final

绝对线程安全,完全符合线程安全定义

相对线程安全,对这个对象的多带带的操作是线程安全的,如Vector,HashTable等

线程兼容,对象本身不是线程安全的,但是可以在调用端正确地使用同步手段才能保证在并发环境下正常使用。

线程对立,无论调用端如何努力,都不可能实现线程安全

线程安全的实现方法

互斥同步

synchronized关键字会在代码块的前后分别形成monitorenter和monitorexit指令,这两个指令需要一个reference对象参数,该锁有一个计数器以实现同步,进入时将计数器+1,退出时-1,本线程可重入,其他线程需阻塞等待。synchronized的缺点是由于Java线程是映射到操作系统的,所以唤醒阻塞一个线程都需要系统帮忙,需要从用户态转到内核态,耗费很多处理器时间。

ReentrantLock对synchronized的优势:

等待可中断

公平锁:必须按照申请锁的时间顺序来一次获得锁

锁绑定多个条件

非阻塞同步

为了解决线程阻塞和唤醒所带来的性能问题,先对共享数据进行操作,如果没有竞争就成功了,否则就补偿(不断重试直到成功)

无同步方案

可重入代码

线程本地存储,把共享数据的范围限制到线程内,ThreadLocalMap以ThreadLocalHashMap为键,以本地线程变量为值的K-V对

锁优化

锁优化的方案有以下几种:

自旋锁:为了减少线程阻塞与唤醒的消耗,线程在被阻塞时可以执行一个忙循环(自旋)

锁消除:对不存在共享数据竞争的锁进行消除

锁粗化:在一个代码块内对一个对象连续的地加锁解锁,就对整个代码块一次性加锁减少性能损耗

轻量级锁:无竞争地情况下使用CAS操作去消除同步使用地互斥量

偏向锁:锁会偏向于第一个获得它地线程

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/68721.html

相关文章

  • Java 虚拟总结面试的你(中)

    摘要:验证过程验证过程的目的是为了确保文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。二虚拟机字节码执行引擎虚拟机的执行引擎自行实现,可以自行制定指令集与执行引擎的结构体系。 本篇博客主要针对Java虚拟机的类加载机制,虚拟机字节码执行引擎,早期编译优化进行总结,其余部分总结请点击Java虚拟总结上篇 。 一.虚拟机类加载机制 概述 虚拟机把描述类的数据从Clas...

    MRZYD 评论0 收藏0
  • Java 虚拟总结面试的你(上)

    摘要:于是这篇博客就针对虚拟机的各个知识点进行归纳。若虚拟机栈请求扩展时无法申请到足够的内存,则抛出异常。类索引用于确定类的全限定名,父类索引用于确定父类的全限定名。字节码指令操作码长度为一个字节,所以总数最多不超过条。 Java虚拟机一直是Java的重难点,一方面由于系统封装得太好,你平常写程序的时候几乎感觉不到它的存在,另一方面了解必要的Java虚拟机工作原理才能对真实工作环境下的bug...

    linkFly 评论0 收藏0
  • Java程序员:不识Jvm真面目,只缘身在增删查改中

    摘要:编译器只需面向,生成能理解的代码或字节码文件。源文件经编译器,编译成字节码程序,通过将每一条指令翻译成不同平台机器码,通过特定平台运行。涨见识,字节码执行过程分析。解决办法减少默认栈的容量来换取更多的线程支持。 前言 JVM是java的核心和基础,在java编译器和os平台之间的虚拟处理器。它是一种基于下层的操作系统和硬件平台并利用软件方法来实现的抽象的计算机,可以在上面执行java的...

    or0fun 评论0 收藏0
  • Java程序员:不识Jvm真面目,只缘身在增删查改中

    摘要:编译器只需面向,生成能理解的代码或字节码文件。源文件经编译器,编译成字节码程序,通过将每一条指令翻译成不同平台机器码,通过特定平台运行。涨见识,字节码执行过程分析。解决办法减少默认栈的容量来换取更多的线程支持。 前言 JVM是java的核心和基础,在java编译器和os平台之间的虚拟处理器。它是一种基于下层的操作系统和硬件平台并利用软件方法来实现的抽象的计算机,可以在上面执行java的...

    ivydom 评论0 收藏0
  • 最最最常见的Java面试总结——第二周

    摘要:与都继承自类,在中也是使用字符数组保存字符串,,这两种对象都是可变的。采用字节码的好处语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。 String和StringBuffer、StringBuilder的区别是什么?String为什么是不可变的? String和StringBuffer、StringBuilder的区别 可变性...

    yearsj 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<