Java线程及线程内存模型
1、说线程从线程的实现说起
线程在操作平台上有三种实现方式:使用内核线程实现方式、使用用户线程实现方式和混合方式
-
使用内核线程实现方式:使用内核线线程高级接口——轻量级进程也就是线程的一对一线程模型[轻量级线程(LWT-Light weight Thread):内核线程(KLT-Kernal Thread)=1:1],各种线程操作由内核通过操纵调度器进行系统调用,需要在内核态和用户态之间来回切换,成本高。
-
使用用户线程实现方式:完全建立在用户空间上,系统不能感知,线程操作在用户态完成,消耗低,能支持大规模数量的线程,但实现困难,是一对多线程模型。
-
混合实现方式:完全建立在用户空间上,把轻量级线程作为用户线程和内核线程的桥梁来使用内核的线程调用功能和处理器映射,大大降低了阻塞风险,降低了实现难度,是多对多的线程模型。
值得注意的是,Java Thread类的关键方法都被声明为native,意味着没有使用或无法使用平台无关性手段,由此虚拟机的线程模型取决于其所在的平台特性
2、线程调度
线程调度有两种实现方式:协同式和抢占式
-
协同式:线程完成工作后主动通知其他线程,一旦出现死锁将造成很严重的后果。
-
抢占式:有系统完成资源在线程之间的调度
注意,线程在语言中设置的优先级并不靠谱,最终还是有系统决定 。
3、Java线程内存模型——分硬件缓存访问相似
-
I.内存间的交互操作
-
操作方法: |lock & unlock —> read| & |load | —> | use & assign|—> |store| & |write|
作用范围:主内存 工作内存 执行引擎 工作内存 主内存
-
规则:
-
①不允许read&load,store&write方法必须成对出现
-
②变量的值在工作内存中发生改变后必须同步到主内存,而没有发生改变的时候不允许无故同步到主内存中
-
③一个新变量稚嫩挂在主内存中诞生
-
④对一个变量执行lock操作时会其清空所有工作内存中该变量的值
-
⑤一个变量在同一个时刻只能被一个线程对其lock
-
⑥unlock之前必须将变量同步回主内存
-
-
-
II.先行发生原则:指的是定义的两项操作之间的偏序关系,先发生的操作产生的影响会被后发生的操作看到
-
III.原子性:基本数据类型的读写都是原子性的
-
可见性:volatile,synchronized和final变量对于所有线程都是可见的
-
有序性:线程内表现未串行的语义,线程外才能在指令重排序和工作内存与主内存同步延迟现象。
-
4、Volatile变量
Volitaile修饰的变量具有可见性,其所在的方法禁止指令重排序
-
可见性指的是每次使用前都会刷新,从主内存中重新获取以保证全局一致性
-
使用场景:I.运算结果不依赖变量当前值,或确保只有单一线程修改
II.变量不予其他变量参与不变约束
-
使用例子如下:
volatile boolean shutdownRequested;
public void shutdown(){
shutdownRequested=true;
}
public void dowork(){
while(shutdownRequested){
//do stuff;
}
}
```