暂停线程意味着此线程还可以回复运行。在 Java 多线程中,可以使用 suspend() 方法暂停线程,使用 resume() 方法恢复运行。
public class MyThread 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 Test {
public static void main(String[] args) {
try {
MyThread thread = new MyThread();
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();
}
}
/*
运行结果:
A = 1503631396807 i = 2771279480
A = 1503631401807 i = 2771279480
B = 1503631406807 i = 5576266494
B = 1503631411807 i = 5576266494
*/
}
从结果上看到,线程的确是被暂停了,而且还能够恢复成运行状态。
缺点1:独占,在使用 suspend() 和 resume() 方法时,如果使用不当,会造成公共的同步对象的独占,使其他线程无法访问公共同步对象。
public class SynchronizedObject {
public synchronized void printString() {
if (Thread.currentThread().getName().equals("a")) {
System.out.println("a 线程永远 suspend 了!");
Thread.currentThread().suspend();
}
System.out.println("end");
}
}
public class Run {
public static void main(String[] args) {
try {
final SynchronizedObject object = new SynchronizedObject();
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();
}
}
/*
运行结果:
a 线程永远 suspend 了!
thread2 启动了,但进入不了 printString() 方法!只打印一个 begin
因为 printString() 方法被a线程锁定并且永远suspend暂停了!
*/
}
thread1 执行 printString() 方法符合条件,所以线程 thread1 被暂停了,没有打印出 end(也没有释放 object 对象的锁,导致 thread2 不能执行 printString() 方法)
下面我们再看一个例子:
public class MyThread2 extends Thread {
private long i = 0;
@Override
public void run() {
while (true) {
i++;
}
}
}
public class Test2 {
public static void main(String[] args) {
try {
MyThread2 thread = new MyThread2();
thread.start();
Thread.sleep(1000);
thread.suspend();
System.out.println("main end!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/*
运行结果:
main end!
*/
}
但是如果将 MyThread2 修改成:
public class MyThread2 extends Thread {
private long i = 0;
@Override
public void run() {
while (true) {
i++;
System.out.println(i);
}
}
}
public class Test2 {
public static void main(String[] args) {
try {
MyThread2 thread = new MyThread2();
thread.start();
Thread.sleep(1000);
thread.suspend();
System.out.println("main end!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/*
运行结果:
338787
338788
338789
338790
338791
*/
}
可以看到,结果将不在输出 main end 了,这是为什么?
其实是跟println() 方法有关,该方法是线程安全的。当 thread 执行该方法时持有方法的锁,thread.suspend() 之后,并没有释放锁,所以 main线程中吃吃不能输出 main end。
缺点2:不同步,在使用 suspend() 和 resume() 方法也容易出现因为线程的暂停而导致数据不同步的情况
public class MyObject {
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();
}
}
public void printString() {
System.out.println(username + " " + password);
}
}
public class Run2 {
public static void main(String[] args) throws InterruptedException {
final MyObject myObject = new MyObject();
Thread thread1 = new Thread() {
@Override
public void run() {
myObject.setValue("a", "aa");
}
};
thread1.setName("a");
thread1.start(); //启动线1,run方法中 username 由 1 变为 a,输出 停止a线程。同时暂停 thread1(没有释放对象myOjbect.setValue()的锁)
Thread.sleep(500);
Thread thread2 = new Thread() {
@Override
public void run() {
myObject.printString();
}
};
thread2.start();//启动线程2,运行printString() 方法,myOjbect.username 已经被 thread 改边为 a
}
/*
运行结果:
停止 a 线程!
a 11
*/
}
总结:
1. suspend() 和 resume() 方法可以暂停线程、重新启动线程,但是有缺陷。
2. 缺陷一:独占,在使用 suspend() 和 resume() 方法时,如果使用不当,会造成公共的同步对象的独占,使其他线程无法访问公共同步对象
3. 缺陷二:不同步,在使用 suspend() 和 resume() 方法也容易出现因为线程的暂停而导致数据不同步的情况