当前位置: 代码迷 >> 综合 >> stop()、suspend()、resume() 弃用的原因(缺点)
  详细解决方案

stop()、suspend()、resume() 弃用的原因(缺点)

热度:88   发布时间:2024-01-31 13:12:31.0

根本原因:线程不安全,可能会出现数据不同步

一、stop() 方法

stop() 方法可以停止一个正在运行的线程,它会立即释放CPU资源和释放锁,是不安全的,可能会导致数据不同步和一些清理性的工作得不到完成,如:关闭文件,关闭连接等,这个方法在Java中已废用。
使用 stop() 方法的存在的问题:

  1. 调用 stop() 方法时,会抛出 java.lang.ThreadDeath 异常,但在通常情况下,此异常不需要显式的捕获。
  2. 方法 stop() 已经被作废,因为如果强制让线程停止则可能会使一些清理性的工作得不到完成。另外一种情况就是对锁定的对象进行了“解锁”,导致数据得不到同步的处理,出现数据不一致的问题。(调用 stop() 方法会释放锁,使线程由执行状态转为阻塞状态)
class SynchronizedObject {private String username = "a";private String password = "aaa";public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}synchronized public void printString(String username, String password) throws InterruptedException {this.username = username;Thread.sleep(10000);this.password = password;}
}class MythreadWithStop implements Runnable {private SynchronizedObject synchronizedObject;public MythreadWithStop(SynchronizedObject synchronizedObject) {this.synchronizedObject = synchronizedObject;}@Overridepublic void run() {try {synchronizedObject.printString("b", "bbb");} catch (InterruptedException e) {e.printStackTrace();}}
}public class StopTestRun{public static void main(String[] args) throws InterruptedException {SynchronizedObject synchronizedObject = new SynchronizedObject();MythreadWithStop mythread = new MythreadWithStop(synchronizedObject);Thread thread = new Thread(mythread);thread.start();Thread.sleep(500);thread.stop();System.out.println(synchronizedObject.getUsername() + " " + synchronizedObject.getPassword());}
}

分析:
线程 MythreadWithStop 执行完 this.username = username 后,此时username = b,password = aaa,调用 sleep() 方法让当前线程睡眠 10s,线程睡眠时,释放CPU资源,Main线程获取到CPU调度获取到时间片,Main线程继续往下执行,调用 stop() 方法,释放 thread 线程。printString() 方法不再往下执行。
Main方法中最后的打印结果为:b aaa

二、suspend() 和 resume() 方法

1. suspend() 暂停线程的执行
2. resume() 恢复线程的执行

缺点:
1) suspend() 需要与 resume() 搭配使用,使用不当时,极易造成公共的同步对象的独占,使得其他线程无法访问公共同步对象。suspend() 暂停线程时,被暂停的线程还会继续的占用同步对象,不释放锁。
2)在使用 suspend() 和 resume() 方法时,也容易出现因为线程的暂停而导致数据不同步的情况。

class MyThread extends Thread{private int i = 0;@Overridepublic void run() {while (true){System.out.println(i++);}}
}public class SuspendAndResumeRun {public static void main(String[] args) throws InterruptedException {MyThread thread = new MyThread();thread.start();Thread.sleep(1000);thread.suspend();System.out.println("main end");}
}

输出结果:输出一些数字后,停止执行,Main 函数中 “main end” 没有被输出。
要了解原因,首先先了解一下 println 方法的源码:在这里插入图片描述
由源码我们可以发现,println() 方法是一个同步方法。它的锁对象是 PrintStream 对象。

下面分析上面的例子为什么 “main end” 不会被输出。当线程 thread 获得CPU调度后,run() 方法被执行,执行 println() 方法输出 i,println() 方法内部获取 PrintStream 对象作为同步锁,在某个时刻,suspend() 方法被调用,此时 println() 方法还占用着 PrintStream 对象,导致 Main 方法中的 println() 方法一直获取不到 PrintStream 对象锁,从而不能进入同步代码块,线程一直处于阻塞状态。

关于println() 方法使用的同步锁对象是否是同一个对象,可以这样进行验证。

class MyThread extends Thread{private int i = 0;@Overridepublic void run() {while (true){System.out.println(i++);if (i == 1){break;}}}
}public class SuspendAndResumeRun {public static void main(String[] args) throws InterruptedException {MyThread thread = new MyThread();thread.start();Thread.sleep(1000);//thread.suspend();System.out.println("main end");}
}

首先在 println() 方法内部打上断点。
在这里插入图片描述
debug 启动运行 Main 方法,从 debug 的运行结果我们可以发现 println() 方法使用的同步锁对象是同一个对象。
在这里插入图片描述
在这里插入图片描述

  相关解决方案