- 进程线程
进程是资源调度的基本单位
线程是cpu调度的基本单位
一个进程可以包含一个或多个线程,共享进程资源 - 并行并发
concurrent:并发
真正同时运行(多cpu):并行
时间片轮转运行(但cpu):并发
并发:是同一时间应对多件事情的能力
并行:是同一时间动手做多件事情的能力 - 同步异步
需要等待结果返回,才能继续运行就是同步
不需要等待结果返回,就能继续运行就是异步
JMH性能测试工具
- 线程创建
- 继承Thread类,重写run方法
- 传实现Runnable接口对象,执行Runnable的run方法(与Thread类解耦,任务与类分开)
- 传FutureTask对象(对象创建时需要传入实现Callable接口的对象),处理有返回值情况
查看进程线程方法
windows:
- 任务管理器
- tasklist查看进程
- taskkill杀死进程
linux:
- ps -fe查看所有进程
- ps -fT -p <PID> 查看某个进程的所有线程
- kill 杀死进程
- top按大写H切换是否显示线程
- top -H -p <PID>查看某个进程的所有线程
java
- jps查看所有java进程
- jstack <PID> 参看某个java进程的所有线程状态
- jconsole查看某个java进程中线程的运行情况(图形界面)
线程上下文切换
- 线程的cpu时间片用完
- GC
- 有更高优先级的线程需要运行
- 线程自己调用了sleep、yield、wait、join、park、synchronized、lock等方法
常见方法
start():启动一个新线程(进入就绪列表,不能多次调用)
run():新线程启动后会调用这个方法(还是父线程执行)
join():等待线程运行结束
join(long n):等待线程结束,最多等待n毫秒
getId():获取线程id
getName(String):获取线程名
getPriority():获取线程优先级
setPriority(int):设置线程优先级
getState():获取线程状态
isInterrupted():是否被打断
isAlive():是否存活
interrupt():打断线程(把休眠的线程叫醒)
currentThread():获取当前正在执行线程(static)
sleep(long n):休眠线程n毫秒(static)
yield():提示线程调度器让出当前线程对CPU的使用(static)
sleep与yield
sleep
- 调用sleep会让当前线程进入TimedWaiting状态
- 其他线程可以使用interrupt方法打断正在睡眠的线程,此时sleep方法会抛出InterruptedException
- 休眠结束后的线程未必立刻得到执行
- 建议用TimeUnit的sleep代替Thread的sleep来获得更好的可读性
TimeUnit.SECONDS.sleep(long time)
yield
- 调用yield会让当前线程从Running进入Running就绪状态,然后调度执行其他线程
- 具体实现依赖OS的任务调度器
线程优先级
- 线程优先级会提示调度器有限调度该线程,但它仅仅是一个提示,调度器可以忽略它
- 如果cpu比较忙,那么优先级高的线程会获得更多的时间片,但空闲时,优先级几乎没有什么作用
防止CPU占用100%
- 使用sleep,给其他线程使用CPU的时间
- 可以使用wait或变量条件达到类似的效果
- 不同的是,后两种都需要加锁,并且需要相应的唤醒操作,一般适用于要进行同步的场景
- sleep适用于无需锁同步的场景
sleep、wait、join抛出异常的同时,中断标记位会被自动清除(变回 false)
两阶段终止模式
错误思路:stop(无法释放共享资源)、System.exit(int)(停止整个进程)
使用interrupt和isInterrupt实现
interrupted() 返回打断标记并清除(static)
而isInterrupt不会清除
打断park线程
LockSupport.park()
打断后不会抛出异常,并且将打断标记设置为true
注意之后park会无效(可以用Thread.interrupted()方法将打断标记设置为false)
不推荐使用的方法
stop() :停止线程运行 (使用二阶段终止模式)
suspend(): 挂起(暂停)线程运行(wait方法,会释放锁)
resume():恢复线程运行(notify唤醒)
原因:它们绕过了线程同步机制,直接粗暴控制线程生命周期
主线程与守护线程
默认情况下,java进程需要等待所有线程都运行结束,才会结束,有一种特殊的线程叫守护线程,只要其他非守护线程运行结束了,即使守护线程的代码没有执行完,也会强制结束
例子:
垃圾回收线程(当程序停止,垃圾回收线程也会停止)
线程五种状态
从操作系统层面描述
- 初始状态:仅是在语言层面创建了线程对象,还未与操作系统线程关联
- 可运行状态:指该线程已经创建(与操作系统线程关联),可以由CPU调度执行
- 运行状态:指获取了CPU时间片运行中的状态
- 阻塞状态:
- 如调用了阻塞API,如BIO读写文件,这时该线程实际不会用到CPU,会导致线程上下文切换,进入阻塞状态
- 等BIO操作执行完毕,会由操作系统唤醒阻塞线程,转换至可运行状态
- 终止状态:表示线程已经执行完毕,生命周期已结束
线程六种状态
从java api层面描述的
根据Thread State枚举,分为六种状态
- new:线程刚刚创建,未调用start方法
- Runnable:包含os层面的可运行状态、运行状态、阻塞状态
- terminated:终止状态
- blocked:竞争锁失败(阻塞)
- waiting:如join
- timed_waiting:如sleep