TPS 每秒处理事务数(Transactions)
如何提升计算机的处理能力:
1、多任务处理(多线程?):cpu速度远大于内存和磁盘,为了不让cpu阻塞,可以让cpu多任务处理。
2、内存和cpu之间增加高速缓存Cache(会带来缓存一致性问题,需要协议、抽象出来就是内存模型)
3、处理器的乱序执行(out of order execution),Java虚拟机中有类似的指令重排序(Instructin Reorder)
缓存一致性 —> 缓存一致性协议
为保证处理器内部的运算单元能够尽量被充分利用—>乱序执行优化
JVM的及时编译器也有类似的指令重排序优化
12.3 Java内存模型
Java Memory Model JMM 为了屏蔽硬件和操作系统的 内存访问差异
JDK1.5 之后 JMM开始完善
主内存与工作内存:
Java内存模型规定所有变量都存储在主内存中,每条线程还有自己的工作内存,线程的工作内存中保存了该线程使用到的变量的主内存副本拷贝,线程对变量的所有操作(读取、赋值等)都必须在工作内存中进行,而不能直接读写主内存中的变量
内存间交互操作:
Java内存模型定义了8种原子操作,jvm要保证每一个操作为原子操作
lock,(锁定,作用于主内存的变量) unlock,(解锁,作用于主内存的变量) read(读取,作用于主内存), load(载入,放入到工作内存中), use(作用于工作内存的变量),
assign(赋值,作用于工作内存),
store(存储,作用于工作内存的变量);
write(写入,作用于主内存的变量)
- 如果要把一个变量从主内存复制到工作内存,那就要顺序地执行read和load操作,如果把变量从工作内存同步回主内存,就要顺序地执行store和write操作。
注意java内存模型只要求上述两个操作必须按顺序执行,而没有保证是连续执行。
volatile变量
最轻量级的同步机制
2个重要特性是保证此变量对所有线程可见
- 是禁止指令重排序优化 ```java 1)每次使用之前都要先刷新,执行引擎看不到不一致的情况,可以保证可见性;但volatile变量在各个线程的工作内存中不存在一致性问题,但java里面的运算并非原子操作,导致volatile变量的运算在并发下一样是不安全的。 (java内存模型规定,load和use动作连续,store和write动作连续)
2)指令重排从硬件上来讲,指令重排序指CPU采用了允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理。但并不是说指令任意重排,CPU需要能正确处理指令依赖情况以保障程序能得出正确的执行结果
性能方面:volatile的读操作的性能消耗与普通变量几乎没有差别,但是写操作则可能会慢一些,因为他需要在本地代码中插入许多内存屏蔽指令来保证处理器不发生乱序执行。
以下场景适用volatile:<br />1)运算结果并不依赖变量的当前值,或者能够保证只有单一的线程修改变量的值;<br />2)变量不需要与其他的状态变量共同参与不变约束;
- 内存屏障 重排序时不能将后面的指令重排序至内存屏障之前的位置
- 一个特定的空操作:使得本CPU的Cache插写入内存(store and wirte)
> 可见性
> 原子性
> 有序性
```java
volatile的特殊规则:
read(读取,作用于主内存),
load(载入,放入到工作内存中),
use(作用于工作内存的变量),
这三个必须连在一起用,即每次使用前该量前,都要从主存中读取该量 的最新值
assign(赋值,作用于工作内存),
store(存储,作用于工作内存的变量);
write(写入,作用于主内存的变量)
这三个必须连在一起用,即每次修改后,都必须将该量及时同步至主存中
long和double
非原子协定,64位数据类型,load,store,read和write操作可以不保证原子性。(目前商用jvm的实现几乎都选择把64位数据的读写操作作为原子操作来对待)
三个特性的理解(原子性、可见性和有序性)
原子性:
- JMM保证对基本数据类型的访问,是具有原子性的
- monitorenter monitorexit 反映到Java关键字是syncronized
可见性:
- java内存模型是通过变量修改后将新值同步回主存,在变量读取前从主存刷新变量值这种依赖主存作为传递媒介的方式来实现可见性的。
- 可以实现可见性的关键字:volatile,synchronized,final(this引用逃逸除外)
- synchronized:对一个变量unlock之前,必须将次变量同步至主内存中
- final:没有发生this引用逃逸时,别的线程都能访问到final字段的值
有序性:
- 如果在本地线程内观察,所有操作都是有序的;如果在一个线程中观察另一个线程,所有的操作都是无序的;
- 可以实现有序性的关键字:volatile,synchronized
综上,synchronized是一个万能的关键字,在原子性、可见性、有序性上都可以支持到。
先行发生原则happens-before
指的是java内存模型中定义的两项操作之间的偏序关系,如果说操作A先行发生于操作B,其实就是说在发生操作B之前,操作A产生的影响能被操作B观察到,“影响”包括修改了内存中共享变量的值、发送了消息、调用了方法等。
java内存模型下的“天然的”先行发生关系:
1)程序次序规则:一个线程,代码顺序(控制流顺序);
2)管程锁定规则:
3)volatile变量规则:写操作先行发生于后面的读操作
4)线程启动规则:start()方法先行发生于此线程的每一个动作;
5)线程终止规则:join
6)线程中断规则:
7)对象终结规则;初始化先于finalize();
8)传递性;
在这8个先行发生之外的操作,JVM可以对这些操作进行任意重排序
12.4 Java与线程
- 线程的引入,可以把一个进程的资源分配和执行调度分开。
- 线程是执行调度的最小单位
-
线程的实现
Thread类关键方法都是声明为Native的(没有使用与平台有关的手段)
使用内核线程(KLT Kernel Level Thread) LWP 轻量级线程
内核线程:由内核来进行线程切换(Thread Scheduler)
一对一的线程模型
- 使用用户线程,系统不会感知到线程的存在
1:N的线程模型
- 用户线程加轻量级线程混合实现
N:M的线程模型
- Java的线程实现,是一对一的线程模型
- Java定义的线程状态:
- 新建new
- 运行runable
- 无期限等待waiting
- 期限等待timed waiting
- 阻塞blocked
- 结束terminated