进程:程序分配资源的基本单位
线程:是进程的最小单位,每个进程中会有一个主线程来控制其他线程。
QQ程序的执行过程:
QQ程序一般情况下静静的躺在硬盘,当他开始要运行的时候会Load到内存,此时QQ程序换一个名字叫QQ进程,一个程序可以对应2个进程,程序开始运行时,他会找到主线程的第一句话(也就是通常所说的main方法),如果需要数据,则把数据放到CPU里,然后CPU将计算的结果写回来,循环往复,直到程序结束为止。
一个CPU在同一个时间点上只能有1个线程在运行,只不过切换速度非常快,多个线程的运行依赖于CPU分配的时间片,当时间片用完,此线程便会处于挂起状态。(注意,线程的切换也需要时间,线程在挂起时会保存当前状态-上下文)
我们看到的进程的切换,切换的也是不同进程的主线程
上下文切换
CPU通过分配时间片来执行任务,当一个任务的时间片用完,就会切换到另一个任务。在切换之前会保存上一个任务的状态,当下次再切换到该任务,就会加载这个状态。
——任务从保存到再加载的过程就是一次上下文切换。
注意:我们无法控制OS选择执行哪些线程,OS底层有自己规则,如:
- FCFS(First Come First Service 先来先服务算法)SJS(Short Job Service短服务算法)
CPU(central processing unit):中央处理单元,计算机的大脑 。
ALU(aluminum logical unit):算数逻辑单元,CPU内部用来做计算的单元。
Registers:寄存器,访问速度是内存速度的100倍。
PC(program counter):程序计数器,用来存你写的指令。
Cache:缓存,CPU中有一级、二级、三级缓存
CPU中可以有多个核,也叫多核CPU,每个核可以单独跑一个线程。
就拿下面的二核CPU举例
这里CPU的2个核心共用一个3级缓存,如果某个服务器有多个CPU的话,则多个CPU共享一个主内存。
今,内存中有个x,现在要把他放到寄存器里,让CPU去做计算,首先去L1找,没有则去L2找,还没有去L3找,都没有则去内存找,找到后,分别向L3、L2、L1(注意顺序)中缓存x值以便下次使用,然后将x放到寄存器开始做计算,下次再找x直接从缓存中取就可以了。(注意CPU取x的时候顺便连x旁边的数据也取了【缓存行】,提高效率)。
缓存行:缓存用来管理数据的最基本单位。目前采用缓存行的大小为64bytes(最大64bytes)
缓存一致性
当一个电脑中cpu有多个核时一个核想从内存中取x进行更改,而另一个核想从内存中取y进行更改,而x和y都在一个缓存行中,此时cpu内部会有一种通信机制来保证缓存的一致性。
对于缓存一致性,不同的cpu有不同的协议来保证缓存一致性(维护缓存一致性也需要时间)
缓存行对齐原理:缓存行最大64bytes。
同一个缓存行会出现和其他核共享数据的情况(就是cpu的多个核共享一个缓存行)
java对象的初始化比c++变量的初始化慢一些,因为其有一个为属性赋初值的过程,而c++在分配新内存空间的时候里面的变量很可能是之前存在过的具体变量,这也意味着java相对于c++来说慢一点,但是安全一点。
单线程下指令重排序保证只要保证了数据一致性就可以换指令顺序
Java对象由三个部分组成:对象头、实例数据、对齐填充。
对象头由两部分组成,第一部分存储对象自身的运行时数据:哈希码、GC分代年龄、锁标识
状态、线程持有的锁、偏向线程ID(一般占32/64 bit)。第二部分是指针类型,指向对象的
类元数据类型(即对象代表哪个类)。如果是数组对象,则对象头中还有一部分用来记录数
组长度。
实例数据用来存储对象真正的有效信息(包括父类继承下来的和自己定义的)
对齐填充:JVM要求对象起始地址必须是8字节的整数倍(8字节对齐)
JOL(java object layout)java对象布局
使用:导包
org.openjdk.jol jol-core0.16
1.解析这个对象,将其转变为可以打印的格式在把他打印出来(查看对象内部信息)
Object o=new Object(); System.out.println(ClassLayout.parseInstance(o).toPrintable());
控制台打印:
java.lang.Object object internals: OFF SZ TYPE DEscriptION VALUE 0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0) 8 4 (object header: class) 0x200001e5 12 4 (object alignment gap) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
2.查看对象外部信息(包括引用对象)
System.out.println(GraphLayout.parseInstance(o).toPrintable());
控制台 打印
java.lang.Object@60e53b93d object externals:
ADDRESS SIZE TYPE PATH VALUE
d6382698 16 java.lang.Object (object)
Addresses are stable after 1 tries.
查看对象占用空间总大小
System.out.println(GraphLayout.parseInstance(o).totalSize());
锁的案例
在java中把某个对象当成一把锁或者锁定某个对象是指在这个对象头中做了一个锁标记,解锁之后其又回复了之前的状态。
当有一个线程持有这个对象的时候,另外一个线程过来了,其也想申请这把锁,此时他会看锁对象头中是否有锁标记,如果打上了锁标记,说明此锁已经被别的线程占有,此时就得等待锁的释放。
锁升级



