暂停线程

暂停线程意味着此线程还可以恢复运行。在Java多线程中,可以使用suspend()方法暂停线程,使用resume()方法恢复线程。

suspend与resume方法的使用

代码清单1 suspend与resume方法的使用

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
43
44
public class SuspendResumeThread extends Thread {
private long i = 0;
public long getI() {
return i;
}
public void setI(long i) {
this.i = i;
}
@Override
public void run() {
while (true) {
i++;
}
}
}
public class SuspendResumeRun {
public static void main(String[] args) {
try {
SuspendResumeThread thread = new SuspendResumeThread();
thread.start();
Thread.sleep(5000);
// A段
thread.suspend();
System.out.println("A= " + System.currentTimeMillis() + " i=" + thread.getI());
Thread.sleep(5000);
System.out.println("A= " + System.currentTimeMillis() + " i=" + thread.getI());
// B段
thread.resume();
thread.sleep(5000);
// c段
thread.suspend();
System.out.println("B= " + System.currentTimeMillis() + " i=" + thread.getI());
Thread.sleep(5000);
System.out.println("B= " + System.currentTimeMillis() + " i=" + thread.getI());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

从控制台打印的时间上看,线程的确被暂停了,而且还可以恢复成运行的状态。



图1 暂停与恢复线程

suspend与resume方法的缺点–独占

1) 在使用suspend与resume方法时,如果使用不当,极易造成公共的同步对象的独占,使得其他线程无法访问公共同步对象。
代码清单2 suspend与resume独占

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
public class SuspendResumeSynchronizedObject {
synchronized public void printString(){
System.out.println("begin");
if(Thread.currentThread().getName().equals("a")){
System.out.println("a线程永远suspend了!");
Thread.currentThread().suspend();
}
System.out.println("end");
}
}
public class SuspendResumeSynchronizedRun {
public static void main(String[] args) {
try {
final SuspendResumeSynchronizedObject object = new SuspendResumeSynchronizedObject();
Thread thread1 = new Thread() {
@Override
public void run() {
object.printString();
}
};
thread1.setName("a");
thread1.start();
Thread.sleep(1000);
Thread thread2 = new Thread() {
@Override
public void run() {
System.out.println("thread2启动了,但进入不了printString()方法!只打印一个begin");
System.out.println("因为printString()方法被a线程锁定并且永远suspend暂停了!");
object.printString();
}
};
thread2.start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}



图2 独占并锁死了printString方法

2) 还有另外一种独占锁的情况也要格外注意,稍有不慎,就会掉进“坑”里。
代码清单3 另外一种独占锁的情况

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
public class SuspendResumeLockThread extends Thread {
private long i = 0;
@Override
public void run() {
while (true) {
i++;
//System.out.println(i);
}
}
}
public class SuspendResumeLockRun {
public static void main(String[] args) {
try {
SuspendResumeLockThread thread=new SuspendResumeLockThread();
thread.start();
Thread.sleep(1000);
thread.suspend();
System.out.println("main end!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

上面输出如下:



图3 控制台打印main end信息

将代码清单3中SuspendResumeLockThread类中//System.out.println(i);注释符//去掉。
再次运行程序,控制台不打印main end,运行结果如下。



图4 不打印main end信息

出现这样情况的原因是,当程序运行到println()方法内部停止时,同步锁未被释放。方法println()源代码如图5所示。



图5 锁不释放

这导致当前PrintStream对象的println方法一直呈”暂停”状态,并且“锁未释放“,而main()方法中的代码System.out.println("main end!");迟迟不能执行打印。
虽然suspend()方法是国期作废的方法,但还是有必要研究它过期作废的原因,这是很有意义的。

suspend与resume方法的缺点—-不同步

在使用suspend与resume方法时也容易出现线程的暂停而导致数据不同步的情况。
代码清单4 数据不同步

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
public class SuspendResumeObject {
private String username = "1";
private String password = "11";
public void setValue(String u, String p) {
this.username = u;
if (Thread.currentThread().getName().equals("a")) {
System.out.println("停止a线程!");
Thread.currentThread().suspend();
}
this.password = p;
}
public void printUsernamePassword() {
System.out.println(username + " " + password);
}
}
public class SuspendResumeNoSameValueRun {
public static void main(String[] args) throws InterruptedException {
final SuspendResumeObject myObject = new SuspendResumeObject();
Thread thread1 = new Thread() {
@Override
public void run() {
myObject.setValue("a", "aa");
};
};
thread1.setName("a");
thread1.start();
Thread.sleep(500);
Thread thread2 = new Thread() {
@Override
public void run() {
myObject.printUsernamePassword();
};
};
thread2.start();
}
}

程序运行的结果出现值不同步的情况,所以在程序中使用suspend()方法要格外注意。



图6 运行结果

Java多线程编程核心技术源代码

Adhere to the original technology to share, your support will encourage me to continue to create!