JAVA 多线程编程之 suspend、resume 废弃的原因 时间: 2018-03-22 17:57 分类: 多线程,JAVA ####前言 在较高的 JDK 版本中,我们可以看到`Thread`类中的`suspend`与`resume`方法都被加上了`Deprecated`注解,这意味着告诉我们不再建议使用这两个方法了,之所以不建议使用,原因有二: * 独占资源锁 * 数据不同步 ####举例说明 首先来分析下出现死锁的情况,也就是独占资源锁: ```java public class SuspendResumeTest { static class MyThread extends Thread { private long i = 0; @Override public void run() { while (true) { i++; System.out.println(i); } } } public static void main(String[] args) throws InterruptedException { MyThread myThread = new MyThread(); myThread.start(); Thread.sleep(1000); myThread.suspend(); System.out.println("main end!"); } } ``` 试猜想下程序最后会输出`main end!`吗? 答案是:不会。这就是 suspend、resume 使用不当可能会出现的问题,下面解释下为什么。 大家都知道 suspend 是暂停线程的意思,按道理执行完 suspend 会继续执行后面的代码,但是这里却阻塞了,关键还是得看 `System.out.println` 这个方法: ```java public void println(String x) { synchronized (this) { print(x); newLine(); } } ``` 看到没有,里面有个监视器`synchronized`对代码块进行了同步,当线程代码在执行到这个同步代码块里面未退出之前,调用`suspend`方法的话,将会把线程暂停,并且锁得不到释放,所以后面的`main end!`输出代码将会被阻塞,导致死锁。 再来看看什么时候会出现数据不同步。 ```java public class SuspendResumeTest { static class User { private String username = "default username"; private String password = "default password"; public void setValue(String username, String password) { this.username = username; if (Thread.currentThread().getName().equals("1")) { System.out.println("暂停1线程"); Thread.currentThread().suspend(); } this.password = password; } public void print() { System.out.println(username + ", " + password); } } public static void main(String[] args) throws InterruptedException { final User user = new User(); Thread t1 = new Thread() { @Override public void run() { user.setValue("zero", "new password"); } }; t1.setName("1"); t1.start(); Thread.sleep(1000); user.print(); } } ``` 还是老样子,想象一下最终输出结果。 结果如下: > 暂停1线程 zero, default password 这个程序只是用来说明`suspend`使用不当会出现这种数据不同步的问题,或许你会说你不会写出上面那样的傻逼代码,那如果是下面这种呢: ```java public class SuspendResumeTest { static class User { private String username = "default username"; private String password = "default password"; public void setValue(String username, String password) { this.username = username; try { //模拟一个耗时操作 Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } this.password = password; } public void print() { System.out.println(username + ", " + password); } } public static void main(String[] args) throws InterruptedException { final User user = new User(); Thread t1 = new Thread() { @Override public void run() { user.setValue("zero", "new password"); } }; t1.setName("1"); t1.start(); Thread.sleep(1000); t1.suspend(); user.print(); } } ``` 结果和第一种差不多,数据未能同步。所以在程序中使用`suspend`方法要格外注意。 这里其实并未对`resume`为什么被废弃作出解释,因为`suspend`与`resume`正确使用方法总是成对使用的,`suspend`都被废弃了,那么`resume`也就没有了存在的必要。 标签: 多线程