1.suspend:挂起,resume:恢复
2.使用suspend()可以将线程挂起,线程处于暂停状态,使用resume()可以将线程恢复运行。
但这两个 API 是过期的,也就是不建议使用的。不推荐使用 suspend() 去挂起线程的原因,是因为 suspend() 在导致线程暂停的同时,并不会去释放任何锁资源。其他线程都无法访问被它占用的锁。直到对应的线程执行 resume() 方法后,被挂起的线程才能继续,从而其它被阻塞在这个锁的线程才可以继续执行。
但是,如果 resume() 操作出现在 suspend() 之前执行,那么线程将一直处于挂起状态,同时一直占用锁,这就产生了死锁。而且,对于被挂起的线程,它的线程状态居然还是 Runnable。
总的来说:在使用suspend()与resume()方法时,如果使用不当,极容易造成公共的同步对象的独占,使得其他线程无法访问公共同步对象。(出现死锁)
3.实例:
package com.springboot.thread;
public class ResumeAndSuspend implements Runnable{
private static long i=0;
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
while (true){
i++;
}
}
public static void main(String[] args) {
try {
Thread thread = new Thread(new ResumeAndSuspend());
// 为了搞清楚当前到底有几个线程 我把线程名字打出来 我们都应该知道 一个java application启动时候主线程必须要启动
System.out.println(Thread.currentThread().getName());
//线程一(Thread-0)开始启动
thread.start();
//睡眠当前线程(main) 这里着重理解
// 当我们的主线程睡眠的时候 thread-0 并没有停止 他继续执行 所以在这5s内i一直在增加
Thread.sleep(5000);
//线程thread-0 被暂停
thread.suspend();
//i is 2509418520
System.out.println("i is "+ i);
//睡眠当前线程(main)
Thread.sleep(5000);
//i is 2509418520
//前后两处的i值是一样的 说明我们的thread-0确实被暂停了
System.out.println("i is "+ i);
//thred-0 恢复执行 继续做++ 操作
thread.resume();
Thread.sleep(5000);
/*i is 5070468571*/
System.out.println("i is "+ i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果:
注: 这么详细的注释 我太良心了!
我们看截图,显示java application一直处于运行中,所以在次 我们是不是应该想想此时到底有几个线程再执行?
首先我们得知我们的thread-0线程resume以后并没有停止他,所以我们可以100%肯定thread-0一定在执行,同时有我们还应该知道一点:在java中,每次程序运行至少创建2个线程。一个是main线程,一个是垃圾回收线程。(面试贼容易问)所以我们可以肯定此时有三个线程在执行,他们分别是GC线程、main线程、thread-0线程。
4.问题与思考:在此实例中,当我们的thread-0线程处于suspend状态时,我们再增加一个线程做i++操作,我们的i会增加吗?
像这样:
package com.springboot.thread;
public class ResumeAndSuspend implements Runnable{
private static long i=0;
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
while (true){
i++;
}
}
public static void main(String[] args) {
try {
Thread thread = new Thread(new ResumeAndSuspend());
Thread thread1 = new Thread(new ResumeAndSuspend(),"Thread-1");
// 为了搞清楚当前到底有几个线程 我把线程名字打出来 我们都应该知道 一个java application启动时候主线程必须要启动
System.out.println(Thread.currentThread().getName());
//线程一(Thread-0)开始启动
thread.start();
//睡眠当前线程(main) 这里着重理解
// 当我们的主线程睡眠的时候 thread-0 并没有停止 他继续执行 所以在这5s内i一直在增加
Thread.sleep(5000);
//线程thread-0 被暂停
thread.suspend();
thread1.start();
//i is 2509418520
System.out.println("i is "+ i);
//睡眠当前线程(main)
Thread.sleep(5000);
//i is 2509418520
//前后两处的i值是一样的 说明我们的thread-0确实被暂停了
System.out.println("i is "+ i);
//thred-0 恢复执行 继续做++ 操作
thread.resume();
Thread.sleep(5000);
/*i is 5070468571*/
System.out.println("i is "+ i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
我们加入了线程一(Thread-1)。
如果我们不是真正的理解suspend与resume的话,我们可能会认为他会占用资源,进而得出i不会增加的结论!
然而,有时候事实却会给你反手一个耳光,打的你啪啪响!
我们看运行结果:
我们可以看到,他们的结果是不一样的,是不是我们了解到的知识是假的呢?
当然不是,在使用suspend()与resume()方法时,如果使用不当,极容易造成公共的同步对象的独占,使得其他线程无法访问公共同步对象。《java多线程编程核心技术》
抓住重点,人家说的是:极容易造成公共的同步对象的独占!(注意,这里是极容易造成独占,并没有说一定会造成独占,所以这是个概率事件,需要很多次试验)
所以我们想要达到预期效果我们应该如何做呢?
代码如下:
package com.springboot.thread;
public class ResumeAndSuspend implements Runnable{
private static long i=0;
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
this.addI();
}
//保证我们addI是一个同步方法
synchronized public void addI(){
while (true){
i++;
}
}
public static void main(String[] args) {
try {
Thread thread = new Thread(new ResumeAndSuspend(),"Thread-0");
Thread thread1 = new Thread(new ResumeAndSuspend(),"Thread-1");
// 为了搞清楚当前到底有几个线程 我把线程名字打出来 我们都应该知道 一个java application启动时候主线程必须要启动
System.out.println(Thread.currentThread().getName());
//线程一(Thread-0)开始启动
thread.start();
//睡眠当前线程(main) 这里着重理解
// 当我们的主线程睡眠的时候 thread-0 并没有停止 他继续执行 所以在这5s内i一直在增加
Thread.sleep(5000);
//线程thread-0 被暂停
thread.suspend();
thread1.start();
//i is 2509418520
System.out.println("i is "+ i);
//睡眠当前线程(main)
Thread.sleep(5000);
//i is 2509418520
//前后两处的i值是一样的 说明我们的thread-0确实被暂停了
System.out.println("i is "+ i);
//thred-0 恢复执行 继续做++ 操作
thread.resume();
Thread.sleep(5000);
/*i is 5070468571*/
System.out.println("i is "+ i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果:无!
参考资料:
《java多线程编程核心技术》