一、基本概念
1.多线程有什么用?
发挥多核CPU的优势、防止阻塞、业务建模
2.线程的底层实现
使用内核线程实现、用户线程实现、用户线程加轻量级混合实现
3.线程调度
协同式调度,优点实现简单,没有线程同步问题,由于线程要把自己的事情干完后才会进程线程切换,切换操作对线程自己是可知的,所有没有什么线程同步问题,Lua语言中的“协调例程”就是这类实现。缺点 线程执行时间不可控,甚至一个线程编写有问题,一直不告知系统进行线程切换,那么程序就会一直阻塞在那里。
抢占式线程调度,线程的执行时间是可控的,也不会有一个线程导致整个进程阻塞的问题,JAVA使用的线程调度就是抢占式的
4.进程&线程
进程是任务调度,资源分配的最小单位,不同进程之间互相隔离,互不影响
线程是进程的最小执行单元
二、线程的状态
新建(NEW):创建后尚未启动的线程处于这种状态
运行(Runable): Runable包括了操作系统线程状态中的Running和Ready,也就是处于此状态的线程有可能正在执行,也有可能正在等待CPU为它分配时间片
无限期等待(Waiting):处于此种状态的线程不会被分配CPU,它们要等待被其他线程显示的唤醒。
限期等待(Time Waiting):处于此种状态的线程也不会被分配CPU执行时间,不过无须等待被其他线程显示地唤醒,在一定的时间之后它们会由操作系统自动唤醒。
阻塞(Blocked):线程被阻塞了,阻塞状态与等待状态的区别是:阻塞状态在等待获取一个排它锁,这个事件在另外一个线程放弃这个锁的时候发生;而”等待状态“则是在等待一段时间,或者唤醒动作的发生,在程序等待进入同步区域的时间,线程将进入这种状态
结束(Terminated):已终止线程的线程状态,线程已经结束执行
三 、锁
按照锁的状态、锁的特性、锁的设计 JAVA中的锁可分类为:公平/非公平锁,独自/共享锁,分段锁,悲观/乐观锁,可重入锁,偏向锁/轻量级锁/重量级锁,自旋锁。
死锁的四个条件:互斥条件,不可抢占条件,占有且申请条件,循环等待条件
锁优化的四个标准:减小锁的持有时间,锁粒度的优化(细化/粗化),锁分离(读写锁/分段锁),无锁(线程安全容器/CAS)
四、内存模型
1.工作内存&主内存
线程之间的共享变量(实例域、静态域和数据元素)存储在主内存(Main Memory)中,每一个线程都有一个私有的本地内存(Local Memory),本地内存中存储了该线程以读写共享变量的副本
2.8种原子操作指令
lock,unlock,read,load,use,assign,write,store
3.内存屏障
内存屏障是一组处理器指令,用于实现对内存操作的顺序限制,包括LoadLoad,LoadStore,StoreLoad,StoreStore共四种屏障,由前面的8种操作指令组成。
JAVA编译器生成指令序列的适当位置插入内存屏障指令来禁止特定类型的处理器重排序,从而让程序按我们预想的流程去执行,内存屏障是与相应的内存重排序对应的。
4.happens-before
Happens-Before的八个规则(摘自《深入理解Java虚拟机》12.3.6章节):
程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作;
管程锁定规则:一个unLock操作先行发生于后面对同一个锁的lock操作;(此处后面指时间的先后)
volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作;(此处后面指时间的先后)
线程启动规则:Thread对象的start()方法先行发生于此线程的每个一个动作;
线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行;
线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生;
对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始;
传递性:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C;
5.重排序
五、JUC
...