一、java线程生命周期
处于休眠状态(blocked、waiting、timed_waiting)的线程,没有CPU的使用权。
二、Runnable状态和休眠状态之间的状态转换
三、Runnable状态到Terminated状态
线程执行完run()方法后,会自动切换到terminated状态;
线程执行过程中,有时我们需要强制终止线程的执行,比如访问一个很慢的网络。强制终止线程有两种方式:stop()和interrupt()
1、stop(),已不建议使用。并且如果线程持有ReentrantLock锁,如果使用stop()终止线程,线程并不会自动调用reentrantLock的unlock()方法去释放锁,会使得该线程立即被杀死,其他线程永远无法获得这个锁。
2、interrupt(),中断线程的正确姿势。使用这个方法,仅仅是通知这个线程,这个线程有机会做一些后续的操作,也可以无视这个通知。
思考:以下代码本意是当前线程被中断之后,跳出while(true)循环,但是其中有问题。
1 Thread th = Thread.currentThread(); 2 while(true) { 3 if(th.isInterrupted()) { 4 break; 5 } 6 // 省略业务代码无数 7 try { 8 Thread.sleep(100); 9 }catch (InterruptedException e){ 10 e.printStackTrace(); 11 } 12 }
以上代码可能出现无限循环,线程在sleep期间被打断了,抛出一个InterruptedException异常,try catch捕捉此异常,应该重置一下中断标示,因为在抛出InterruptedException后会清除中断标志(代表可以接收下一个中断信号了)!
Thread th = Thread.currentThread();
while(true) {
if(th.isInterrupted()) {
break;
}
// 省略业务代码无数
try {
Thread.sleep(100);
}catch (InterruptedException e){
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
四、诊断并发问题的一个重要工具---Java VisualVM
可以通过 jstack 命令或者Java VisualVM这个可视化工具将 JVM 所有的线程栈信息导出来,完整的线程栈信息不仅包括线程的当前状态、调用栈,还包括了锁的信息。例如,我曾经写过一个死锁的程序,导出的线程栈明确告诉我发生了死锁,并且将死锁线程的调用栈信息清晰地显示出来了(如下图)。导出线程栈,分析线程状态是诊断并发问题的一个重要工具。
java Visual VM在java 6之后自带工具,无须独立安装。在安装目录bin下,打开后直接使用。