Java线程调用suspend()后执行resume()无法恢复运行问题咨询
问题根本原因
- 执行时序错位:main线程启动t2后立刻调用
resume(),此时t2还没有运行到suspend()方法位置,唤醒操作先于挂起操作完成,唤醒信号直接丢失。等t2打印完11执行到suspend()时,已经没有任何线程会触发唤醒操作,所以线程永久挂起,不会打印后续内容,程序也无法自动退出。 - 废弃API的固有缺陷:
suspend()和resume()是JDK 1.2就被官方标记为废弃的线程操作方法,调用时如果线程状态不符合预期(比如本次线程还未挂起就调用resume()),就会直接抛出IllegalThreadStateException。同时suspend()挂起线程时不会释放持有的任何锁,极易引发系统死锁,完全不建议在代码中使用。
修复方案
推荐使用java.util.concurrent.locks.LockSupport提供的park()/unpark()方法替代废弃的suspend()/resume()。这组方法不存在信号丢失问题:unpark()可以先于park()执行,会提前给目标线程发放一个运行许可,后续park()执行时如果已经有许可,会直接消耗许可继续运行,不会阻塞,刚好适配你的业务逻辑。
修复后的完整代码如下:
import java.util.concurrent.locks.LockSupport; class Hi extends Thread { public void run(){ try{ for(int i=0; i<=10; i++){ System.out.println("1st: " + (2*i)); sleep(100); } } catch(Exception e){ System.out.println(e); } } } class Hello extends Thread { public void run(){ try { for(int i=0; i<=5; i++){ System.out.println("2nd: " +(2*i+1)); } LockSupport.park(); // 替换原suspend()方法 System.out.println(" Resumes again"); for(int i=6; i<=10; i++){ System.out.println("2nd: " +(2*i+1)); } } catch(Exception e){ System.out.println(e); } } } public class ThreadTest { public static void main(String args[]){ Hi t1 = new Hi(); Hello t2 = new Hello(); t1.start(); try { t1.join(); } catch (Exception e) { e.printStackTrace(); } t2.start(); LockSupport.unpark(t2); // 替换原resume()方法 } }
运行后t2会正常打印完111的奇数,再继续打印1321的奇数,无异常抛出,程序运行完成后自动退出。
如果需要使用传统的wait()/notify()实现,需要额外增加一个挂起状态标记位,唤醒操作先修改标记位,线程挂起前先检查标记位,如果已经收到唤醒信号就无需进入等待,避免信号丢失问题。
内容的提问来源于stack exchange,提问作者Gairik Sajjan
相关产品推荐
相关产品推荐

