并发、并行与串行
- 并发:单核多任务,按时间片轮流交替执行
- 并行:多核多任务,同时进行
- 串行:多个任务按顺序进行
线程与进程
进程是资源分配的基本单位,线程任务调度与执行的基本单位
线程又被称为轻量级进程,同一进程中的线程共享进程的资源,线程之间切换的开销要远小于进程之间的切换
什么是上下文切换
cpu采用的是为每个线程分配时间片并轮转的形式,当千任务在执行完cpu时间片会切换到另一任务前会保存自己的状态,以便下次切换回这个任务可以加载这个任务状态。任务从保存到再加载的过程就是一次上下文切换,计算密集型,可能是
操作系统中消耗最大的操作。
多线程的问题
- 线程多,占用内存高
- 线程管理需要CPU时间跟踪
- 线程之间对共享资源的访问会相互影响,因此要解决竞争共享资源的问题
查找cpu利用率高的线程
- top: 找到利用率最高的进程的pid
- top -H -p pid:找出进程中利用率最高的线程、
- 转16进制
- jstack pid > /tem t.dat:打印进程信息
- 查看该日志文件
-
线程死锁的条件
- 互斥
- 请求保持
- 不可剥夺
- 循环等待
创建线程的方法
- 继承Thread类,重写run方法
- 实现runnable接口,重写run,作为参数传递给Thread类
- 实现callable方法,重写call,作为参数传给FutureTask,再传给Thread,可以获得返回值
- 线程池:全部实现ExectuorService接口
其中Executors工具类提供了一系列方法用于创建线程池
newFixedThreadPool,newSingleThreadExecutor-------容易任务堆积出现溢出
newCachedThreadPool,newScheduledThreadPool-------线程过多出现溢出
FutureTask
运算没结束get方法会一直阻塞
线程生命周期
wait/notify/notifyAll
必须在同步块中调用,wait会释放锁notify要获取锁,他们是object的方法,因为任何一个对象都可以获取多个锁
线程池流程
- 无界队列:一直添加
- 有界队列:
1. Abort:抛出异常
2. Discard:直接丢弃
3. DiscardOldest:丢弃最老的
4. callerrun:由调用线程去处理
Happends-before
- volatile的写操作发生在读操作前
- 线程启动先于该线程的其他操作
- 线程内按顺序
- unlock发生在lock前
- interrupt一定发生在线程的中断前
- 线程内任何操作都先于检测到该线程结束
- 构造先于finalizer前
- 传递性
AQS
一个用来构建锁和同步器的框架
核心思想:
请求的资源空闲,则将请求该资源的线程置为有效线程并将资源锁定,若是被占用,则将其加入等待队列,AQS使用CLH(虚拟双向队列,将线程封装成一个节点并维持节点之间的关系)来实现锁分配
AQS使用一个volatile修饰的共享变量表示同步状态
资源的共享方式:
- 独占:只允许一个线程执行
- 公平锁:按顺序
- 非公平锁:抢占式
- 共享:countdownLatch、cyclicBarrier…
线程池
建议ThreadPoolExecutor来自己手动编写
1. core
2. max
3. queue
4. keepAlive
5. 单位
6. ThreadFactory
7. 拒绝策略