0%

suspend+resume+stop方法

前言:学习Thread的suspend、resume、stop方法

简介

首先说明suspend、resume、stop方法已经被废弃了,因为容易造成线程死锁,suspend挂起不会释放锁,其他线程就会继续请求该资源,造成忙等,可以使用wait、notify替代

suspend

使线程挂起,但是不会释放类似锁这样的资源。

resume

使线程恢复,如果之前没有使用suspend暂停线程,则不起作用。

stop

停止当前线程。不会保证释放当前线程占有的资源。

Stop废弃缘由

该方法具有固有的不安全性。用Thread.stop来终止线程将释放它已经锁定的所有监视器(作为沿堆栈向上传播的未检查ThreadDeath异常的一个自然后果)。

如果以前受这些监视器保护的任何对象都处于一种不一致的状态,则损坏的对象将对其他线程可见,这有可能导致任意的行为。

stop的许多使用都应由只修改某些变量以指示目标线程应该停止运行的代码来取代。目标线程应定期检查该变量,并且如果该变量指示它要停止运行,则从其运行方法依次返回。如果目标线程等待很长时间(例如基于一个条件变量),则应使用 interrupt 方法来中断该等待。

当调用Thread.stop()方法时,会发生下面两件事:

  1. 即刻抛出ThreadDeath异常,在线程的run()方法内,任何一点都有可能抛出ThreadDeath Error,包括在catch或finally语句中。

  2. 会释放该线程所持有的所有的锁,而这种释放是不可控制的,非预期的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class StopDemo {
public static void main(String[] args) {
StopThread thread = new StopThread();
thread.start();
try {
//休眠1秒,确保i变量自增成功
Thread.sleep(1000);
} catch (InterruptedException e) {
//一般会处理中断异常,这里作为例子就直接打印到控制台了
e.printStackTrace();
}
//暂停线程
thread.stop();
while (thread.isAlive()) {//确保线程已经终止

}
//输出结果
thread.print();
}

private static class StopThread extends Thread {
private int i = 0;
private int j = 0;

@Override
public void run() {
synchronized (this) {//增加同步锁,确保线程安全
++i;
try {
//休眠10秒,模拟耗时操作
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
++j;
}
}
public void print() {
System.out.println("i=" + i + " j=" + j);
}
}
}

image-20200111234944982

如上代码与结果,正常运行输出i=1,j=1,但是由于在i++之后j++之前就stop,导致数据出现不一致性

取代Thread.stop

大多数stop的使用,应当被替换为简单修改某些变量来指示其目标线程将停止运行的代码。目标线程应当有规律的检查这些变量。并且,如果这些变量指示其将停止运行,目标线程应当以某种有序的方式从它的run方法返回(这正是Java Tutorial一贯建议的方式)。为了确保停止请求的及时传达,变量必须是volatile的(或者变量的访问被同步)。

例如,假设你的applet包含了start、stop和run方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private Thread blinker;

public void start() {
blinker = new Thread(this);
blinker.start();
}

public void stop() {
blinker.stop();
}

public void run() {
Thread thisThread = Thread.currentThread();
while (true) {
try {
thisThread.sleep(interval);
} catch (InterruptedException e){
}
repaint();
}
}

为了避免使用Thread.stop,你可以把applet的stop和run方法替换成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private volatile Thread blinker;

public void stop() {
blinker = null;
}

public void run() {
Thread thisThread = Thread.currentThread();
while (blinker == thisThread) {
try {
thisThread.sleep(interval);
} catch (InterruptedException e){
}
repaint();
}
}
-------------本文结束感谢您的阅读-------------