# 线程安全实现
- 互斥同步
- 非阻塞同步
- CAS
- AtomicIntger
- 无同步方案
- 栈封闭
- 线程本地存储
# 线程状态
New
Runnalbe
TImeWaiting:限期等待
Blocked(Synchroined Lock)等待获取排它锁,如果其它线程释放了锁就会结束此状态
Waiting(Object.wait,Thread.join,LockSupoport.pack,Object.notify)无限期等待,等待其它线程显示唤醒,否则不会分配时间版
Terminated
# 线程实现方案
- Runnable
- Callable
- 继承Thread
# 线程机制
- Executor
- CachedThreadPool
- FixedThreadPool
- SingleThreadExecutor
- Daemon
- 所有非守护线程结束,程序也就终止,同时杀死所有守护线程
- sleep:休眠正在执行的线程
- yield:当前线程已完成生命周期最重要部分,可以切换其它线程执行
# 线程中断
- InterruptedException:调用一个线程的interrutp方法中断此线程,如果线程在阻塞、限期等待或无限期等待状态,会抛出InterruptedException从而提前结束线程,但不中断IO阻塞和Synchronied锁阻塞
- Interrupted:设置线程中断标记
- Executor中断操作:shudownNow方法相当于调用每个线程的interrupt方法
# 线程协作的方式
- join:当前线程挂起,而不是忙等,直到目标线程结束
- Wait notify notifyAll:调用wait使线程等待某个条件满足,在等待过程中线程会被挂起,当其它线程运行使条件满足时,其它线程调用notify或notifyAll来唤醒挂起的线程 它们只能在同步方法或同步控制块中使用,否则抛出ILLegalMonitorStateException异常 wait挂起期间,会释放锁,如果没有释放,其它线程无法进入对象的同步方法或同步控制块中,就无法执行notify和nitifyAll唤醒挂起的线程,引起死锁
- wait与sleep:wait释放锁,sleep不会;wait在object上,sleep在 Thread上
- Await,signal,signalAll
# Synchronized性能提升
- 锁粗化:减少不必要的unlock和lock,多个连续的锁扩展成范围更大的锁
- 锁消除:通过JIT编译器逃逸分析消除一些没有在当前同步块以外被其它线程共享的数据的锁保护
- 轻量级锁:
- 偏向锁:无锁嬜情况下避免锁获取过程中不必要的cas原子指令
- 适应性自旋
# 进程上下文切换开销
- 直接开销:cpu必须要做的事情
- 切换页表全局目录
- 切换内核态堆栈
- 切换硬件上下文(进程恢复前,必须装入寄存器的数据)
- Ip:instruction pointer,指向当前指令的下一条指令
- Bp:base pointer,用于存放执行中的函数对应的栈帧的栈底地址
- Sp:stack pointer,用于存放执行中的函数对应的栈帧的栈顶地址
- Cr3:页目录基址寄存器,保存页目录表的物理地址
- 刷新TLB
- 系统调度器的代码执行
- 间接开销:缓存不热,穿透到内存IO
# 线程上下文切换开销
轻量级进程,迎合开发者口味,调度上与进程没有区别,只不过轻量级进程可以共享同一内存地址空间、代码段、全局亦是、同一打开文件集合
# 多线程的其它开销
- 缓存失效:线程切换到其它线程,转而去执行不同的代码,原有的缓存就可能失效,重新缓存新的数据
- 协作开销:为保证多线程访问共享数据的安全,可能禁止编译器和cpu重排序等的优化;另外还有为解决可见性带来了主内存与工作内存数据刷新操作
# 用户态与内核态
内存区域
- 内核空间:只有内核程序可以访问
- 用户空间:专门给应用程序使用的内存
用户态和内核态
- 用户态:用户空间的代码被限制只能使用一个局部的内存空间,我们说它在用户态运行
- 内核态:内核空间的代码能访问所有内存,我们称它在内核态运行
系统调用:用户态程序需要执行系统调用,就需要切换到内核态运行。在切换的过程中,用户态程序权限不足,因此会中断执行(也就是Trap),中断发生后,当前cpu执行程序会中断,跳转到中断处理程序。内核完成处理后,主动触发Trap。这样会再次发生中断,切换回用户空间。