1、线程之间的转换
1.1线程的状态一共分为6种
- NEW:线程创建通过new Thread()等等方式
- RUNNABLE:调用了start方法,包括运行、就绪状态
- BLOCKED:获取锁失败进入entryList队列
- WAITING:等待另外一个线程唤醒,通过wait()等方法,进入waitSet等待唤醒
- TIMED_WATING:含有时间的等待
- TERMINATED:线程运行结束终止状态。
1.2线程状态图如下:
- 调用start方法
- wait方法RUNNABLE -> WAITING
- notify interrunpt notifyAll调用方法 WAITING -> RUNNABLE,虽然唤醒了,但是过程是由waitSet进入entryList队列进行cpu的抢夺。
- join():由RUNNABLE -> WAITING(等待另一个线程完成),但是不会释放锁,容易产生死锁问题
- wait(设置等待参数)
- join(设置过期参数)
- sleep(参数)
- notify interrunpt notifyAll唤醒or等待设置时间过期
- 获取锁失败,进入阻塞状态。
- 线程运行结束.
2、线程的活跃性
2.1 死锁
死锁:同时争抢资源,相互等待对方资源释放,最终导致死锁
死锁产生的条件:
- 互斥条件:至少有一个资源是不能共享的,其他线程需要等待该资源的释放。
- 占有和等待
2.2 活锁
活锁:线程并未被阻塞都在运行,但是却直处于一种伪“忙碌等待”,原因是:一个线程改变了另外一个线程的结束条件。
2.3 饥饿
顺序加锁可以解决死锁问题,但是会产生线程饥饿问题,有的线程始终或者很少获得cpu执行。
解决办法:ReentrantLock进行解决。
3、死锁检查工具
3.1 使用 Java 自带工具:jstack
jstack 是 Java 自带的线程转储工具,可以用于检测死锁。
使用方法:
找到运行中 Java 进程的 PID,可以使用 jps 命令:
jps
3.2 使用 JConsole
JConsole 是 JDK 自带的图形化监控工具,也可以检测死锁。
使用方法:
启动 JConsole:
jconsole
连接到目标 Java 应用程序。
切换到 “线程” 面板,如果检测到死锁,会显示相关信息。