0%

JVM.jpg

6. 晚期编译优化

晚期编译优化主要是在运行时做的一些优化手段。

6.1 JIT编译器

在部分的商用虚拟机中,java程序最初是通过解释器(Interpreter) 进行解释执行的,当虚拟机发现某个方法或代码块的运行特别频繁时,就会把这些代码认定为“热点代码”(Hot Spot Code)。为了提高热点代码的执行效率,在运行时,虚拟机将会把这些代码编译成与本地平台相关的机器码,并进行各种层次的优化,完成这个过程的编译器称为即时编译器(Just In Time Compiler)

java虚拟机规范中没有规定即时编译器应该如何实现,也没有规定虚拟机必需拥有即时编译器,这部分功能完全是虚拟机具体实现相关的内容。本文中提及的编译器、即时编译器都是指HotSpot虚拟机内的即时编译器。

阅读全文 »

JVM.jpg

5. 早期编译优化

早期编译优化主要指编译期进行的优化。

java的编译期可能指的以下三种:

  1. 前端编译器:将*.java文件变成*.class文件,例如Sun的Javac、Eclipse JDT中的增量式编译器(ECJ)
  2. JIT编译器(Just In Time Compiler):将字节码变成机器码,例如HotSpot VM的C1、C2编译器
  3. AOT编译器(Ahead Of Time Compiler):直接把*.java文件编译成本地机器码,例如GNU Compiler for the Java(GCJ)、Excelsior JET
阅读全文 »

JVM.jpg

4. 编写高效Java程序

4.1 面向对象

构造器参数太多怎么办?

正常情况下,如果构造器参数过多,可能会考虑重写多个不同参数的构造函数,如下面的例子所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class FoodNormal {

//required
private final String foodName;//名称
private final int reilang;//热量

//optional
private final int danbz;//蛋白质
private final int dianfen;//淀粉
private final int zf;//脂肪

//全参数
public FoodNormal(String foodName, int reilang, int danbz,
int dianfen, int zf, int tang, int wss) {
super();
this.foodName = foodName;
this.reilang = reilang;
this.danbz = danbz;
this.dianfen = dianfen;
this.zf = zf;
}

//2个参数
public FoodNormal(String foodName, int reilang) {
this(foodName,reilang,0,0,0,0,0);
}

//3....6个参数
//

public static void main(String[] args) {
FoodNormal fn = new FoodNormal("food1",1200,200,0,0,300,100);
}
}
阅读全文 »

JVM.jpg

3. 虚拟机执行子系统

3.1 Java跨平台的基础

Java刚诞生的宣传口号:一次编写,到处运行(Write Once, Run Anywhere),其中字节码是构成平台无关的基石,也是语言无关性的基础。

Java虚拟机不和包括Java在内的任何语言绑定,它只与Class文件这种特定的二进制文件格式所关联,这使得任何语言的都可以使用特定的编译器将其源码编译成Class文件,从而在虚拟机上运行。

Screen Shot 2019-12-22 at 4.41.27 PM.png

阅读全文 »

JVM.jpg

2. 垃圾收集器与内存分配策略

垃圾收集(Garbage Collection, GC)是JVM实现里非常重要的一环,JVM成熟的内存动态分配与回收技术使Java(当然还有其他运行在JVM上的语言,如Scala等)程序员在提升开发效率上获得了惊人的便利。理解GC,对于理解JVM和Java语言有着非常重要的作用。并且当我们需要排查各种内存溢出、内存泄漏问题时,当垃圾收集称为系统达到更高并发量的瓶颈时,只有深入理解GC和内存分配,才能对这些“自动化”的技术实施必要的监控和调节。

GC主要需要解决以下三个问题:

  • 哪些内存需要回收?
  • 什么时候回收?
  • 如何回收?
阅读全文 »

JVM.jpg

1. Java内存区域

1.1 运行时数据区

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。主要包括:程序计数器、虚拟机栈、本地方法栈、Java堆、方法区(运 行时常量池)、直接内存。

Screen Shot 2019-12-17 at 9.40.27 PM.png

程序计数器

程序计数器(Program Counter Register)是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。在虚拟机概念模型中,字节码解释器工作时就是通过改变计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

程序计数器是一块“线程私有”的内存,各个线程相互独立存储,互不影响。

阅读全文 »

9.1 CompletableFuture

CompletableFuture是JDK 8中引入的工具类,实现了Future接口,对以往的FutureTask的功能进行了增强。

手动设置完成状态

CompletableFuture和Future一样,可以作为函数调用的契约,当向CompletableFuture请求数据时,如果数据还没有准备好,请求线程就会等待。但是,我们可以手动设置CompletableFuture的完成状态。

下面的例子中,创建了CompletableFuture对象实例进行计算,同时另外一个线程进行等待,接着,模拟等待一段时间之后,设置完成状态为完成,此时等待线程继续执行。

阅读全文 »

8. JMM和底层实现原理

8.1 线程间的通信与同步

线程之间的通信

线程的通信是指线程之间以何种机制来交换信息。在编程中,线程之间的通信机制有两种,共享内存和消息传递。

共享内存的并发模型里,线程之间共享程序的公共状态,线程之间通过写-读内存中的公共状态来隐式进行通信,典型的共享内存通信方式就是通过共享对象进行通信。

阅读全文 »

7. 线程安全

7.1 线程安全的定义

如果多线程下使用这个类,不过多线程如何使用和调度这个类,这个类总是表示出正确的行为,这个类就是线程安全的。

类的线程安全表现为:

  • 操作的原子性
  • 内存的可见性

不做正确的同步,在多个线程之间共享状态的时候,就会出现线程不安全。

7.2 如何保证线程安全

栈封闭

所有的变量都是在方法内部声明的,这些变量都处于栈封闭状态。

比如下面的例子,a和b都是在方法内部定义的,无法被外部线程所访问,当方法结束后,栈内存被回收,所以是线程安全的。

阅读全文 »