一 . Java程序执行流程:
- 1. 首先,要执行我们的java程序,要先写好我们的java源码文件,也就是java代码,之后用编译器(java Complier ),(javac命令编译)把源码成class字节码文件
- 2. 有了字节码文件,要想执行这个字节码文件,需要调用ClassLoader 类加载器,把对应的字节码。文件加载到内存中,也就是(运行时数据区 Runtime Data Area),java内存模型就是说的这一块。
- 3. 之后呢,交由Jvm 执行引擎(ExEcution Engine )便会根据根据运行时数据区中的内容,去执行我们的代码。
二. java内存模型:
根据jvm内存规范,jvm内存共分为:
虚拟机栈, 堆,方法区,程序计数器,本地方法栈五个部分。
程序计数器 :
- 每个线程都有一个程序计数器
- 各线程的程序计数器是线程私有的,互不影响,是线程安全的
- 程序计数器记录线程正在执行的内存地址,以便中断线程恢复执行时再次按照中断指令地址继续执行
虚拟机栈Java Stack :
- 每个线程会对应一个java栈
- 每个Java栈由若干栈帧数组成
- 每个方法对应一个栈帧
- 栈帧在方法运行时,创建并入栈,方法执行完,该栈帧弹出栈帧中的元素作为该方法返回值,该栈帧会被清除
- 栈顶的栈帧叫活动栈,表示当前执行的方法,才可以被cpu执行
- 线程请求的栈深度大于虚拟机所允许深度,将会抛出stackOverFlowError异常
- 栈拓展时无法申请到足够的内存时,就会抛出OutOfMemoryError异常
方法区 :
-
是 java 栈的永久区
- 方法区存放了要加载的类的信息(名称,修饰符),类中的静态变量,类中定义为final类型的常量,类中的Field信息,类中的方法信息
- 方法区是被java线程共享的
- 方法区要使用的内存超过其允许的大小是,会抛出OutOfMemoryError:PremGen space的错误信息
常量池 :
- 是方法区的一部分
- 存放两类数据:字面量和引用量
- 字面量 : 字符串 , final变量等
- 引用量:类/接口,方法和字段的名称和描述符
- 常量池在编译期间就被确定,并保存在已编译的.class文件中
本地方法栈 :与java栈所发挥的作用相似,java栈为JVM执行java方法服务,而本地方法栈为JVM执行Native方法服务。
多线程特性 :
多线程编程保证满足的三个特性:原子性,可见性,有序性。
原子性:一个操作或者多个操作要么全部执行并且执行的过程不会被任何因素打断,要么都不执行。
可见性:当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看到修改的值。这就避免了脏读的情况。对单线程来说,可见性问题是不存在的
有序性:程序执行的顺序按照代码的先后顺序执行
多线程控制类:
为了保证多线程的三个特性 : java引入了很多线程控制机制,下面介绍其中常用的几种
ThreadLocal :线程本地变量
原子类: 保证变量原子操作
Lock类:保证线程有序性
Volatile 关键字:保证线程变量可见性
ThreadLocal :
- 作用 : ThreadLocal提供线程局部变量,即为使用相同变量的每一个线程维护一个该变量的副本,当某些数据是以线程为作用域并且不同线程具有不同的数据副本的时候,就可以考虑采用ThreadLocal,比如数据库连接Connection, 每个请求处理线程都需要,但是又不互相影响,就可以用ThreadLocal实现。
- 常用方法:
- initialValue : 副本创建方法
- get : 获取副本方法
- set : 设置副本方法