使用 suspend 和 resume 暂停和恢复线程

摘要:
suspend()方法用于挂起(暂停)线程,resume()用于重新启动挂起的线程并继续向下运行。尽管线程已成功暂停并恢复,但我们会发现suspend和resume已标记为过时方法,不建议使用。由于线程暂停,使用不同步的suspend和resume方法也很容易导致数据不同步。

suspend 和 resume 的使用

在 Thread 类中有这样两个方法:suspend 和 resume,这两个方法是成对出现的。

  • suspend() 方法的作用是将一个线程挂起(暂停),
  • resume() 方法的作用则是将一个挂起的线程重新开始并继续向下运行。

通过一个例子来看一下这两个方法的使用:

public class SuspendThread {

    public static void main(String[] args) {
        SimpleDateFormat f = new SimpleDateFormat("HH:mm:ss");
        
        try {
            MyThread2 t = new MyThread2();
            t.start();
            Thread.sleep(1000);
            
            //暂停线程
            t.suspend();
            System.out.println("暂停线程:" + 
                            f.format(System.currentTimeMillis()) + 
                            ", num = " + t.getNum());
            Thread.sleep(5000);
            System.out.println("暂停线程5秒后:" + 
                            f.format(System.currentTimeMillis()) + 
                            ", num = " + t.getNum());
            
            //继续线程
            t.resume();
            System.out.println("--恢复线程--");
            Thread.sleep(5000);
            System.out.println("--恢复线程5秒后--");
            
            //再次暂停线程
            t.suspend();
            System.out.println("再次暂停:" + 
                            f.format(System.currentTimeMillis()) + 
                            ", num = " + t.getNum());
            Thread.sleep(5000);
            System.out.println("再次暂停5秒后:" + 
                            f.format(System.currentTimeMillis()) + 
                            ", num = " + t.getNum());
            
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
}

class MyThread2 extends Thread{
    private long num = 0;
    
    public void setNum(long num) {
        this.num = num;
    }
    
    public long getNum(){
        return num;
    }

    @Override
    public void run() {
        while(true){
            num++;
        }
    }
    
}

输出结果:

暂停线程:15:27:21, num = 612874824
暂停线程5秒后:15:27:26, num = 612874824
--恢复线程--
--恢复线程5秒后--
再次暂停:15:27:31, num = 3663392709
再次暂停5秒后:15:27:36, num = 3663392709

从输出结果打印的时间上看来,线程确实被暂停了,而且还能恢复继续运行。

为什么弃用?

虽然现在已经成功的暂停和恢复了线程,但是我们会发现 suspend 和 resume 早已被标注为了废弃方法,并且不推荐使用了。

不释放锁

这是因为 suspend 方法不会释放锁,而如果调用了 suspend 方法的目标线程在挂起时对某一重要的系统资源持有锁,那么在目标线程重新开始之前其他任何线程都无法访问该资源。

public class SynchronizedObject {

    public static void main(String[] args) throws InterruptedException {
        
        final SynchronizedObject object = new SynchronizedObject();
        
        Thread thread1 = new MyThread3(object);
        Thread thread2 = new MyThread3(object);
        
        thread1.setName("thread1");
        thread1.start();
        
        Thread.sleep(1000);
        
        thread2.setName("thread2");
        thread2.start();
        
    }
    
    //使用synchronized实现锁功能
    synchronized public void printString(){
        String threadName = Thread.currentThread().getName();
        
        System.out.println(threadName + " - begin");
        if(threadName.equals("thread1")) {
            System.out.println("thread1 - suspend");
            Thread.currentThread().suspend();
        }
        System.out.println(threadName + " - end");
    }
    
    static class MyThread3 extends Thread {
        SynchronizedObject obj;
        
        public MyThread3(SynchronizedObject obj) {
            this.obj = obj;
        }

        @Override
        public void run() {
            obj.printString();
        }
    }
}

输出结果:

thread1 - begin
thread1 - suspend

从打印的结果来看,虽然 thread2 被启动了,但是并没有进入它的 printString() 方法,这便是因为 printString 方法已经被 thread1 线程锁定并暂定了,导致其他线程无法访问公共代码块。

不同步

使用 suspend 和 resume 方法也容易出现因为线程的暂停而导致数据不同步的问题。

public class TestObject {

    public static void main(String[] args) throws InterruptedException {
        final UserObject obj = new UserObject();
        Thread thread1 = new Thread() {
            public void run() {
                obj.setValue("lisi", "30");
            };
        };
        
        thread1.setName("thread1");
        thread1.start();
        thread1.sleep(500);
        
        Thread thread2 = new Thread(){
            public void run() {
                obj.printValue();
            };
        };
        
        thread2.start();
        
    }
    
    static class UserObject {
        private String name = "zhangsan";
        private String age = "18";
        
        public void setValue(String name, String age) {
            this.name = name;
            if(Thread.currentThread().getName().equals("thread1")){
                System.out.println("暂停 thread1");
                Thread.currentThread().suspend();
            }
            this.age = age;
        }
        
        private void printValue(){
            System.out.println(name + " : " + age);
        }
    }

}

输出结果:

暂停 thread1
lisi : 18

程序运行的结果出现了不同步的情况,所以不再建议使用 suspend 和 resume 方法了。

免责声明:文章转载自《使用 suspend 和 resume 暂停和恢复线程》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇如何跟踪高CPU在用户模式应用程序-现场调试!2019-9-2-visual-studio-2015-warning-MSB3246下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

iOS性能优化:Instruments使用实战

Instruments使用技巧 关于Instruments官方有一个很有用的用户使用Guide,当然如果不习惯官方英文可以在这里找到中文本翻译版本PDF参阅.Instruments 确实是一个很强大的工具,用它来收集关于一个或多个系统进程的性能和行为的数据极为方便,并能及时跟踪随着时间产生的数据.还可以广泛收集不同类型的数据.关于Instrument工具基...

线程同步以及AutoResetEvent

近期在重构老项目时发现有些地方用了AutoResetEvent,于是查了些资料学习整理。 线程同步介绍 即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,而其他线程又处于等待状态,实现线程同步的方法有很多,临界区对象就是其中一种。 同步就是协同步调,按预定的先后次序进行运行。如...

Linux 系统编程 学习:11-线程:线程同步

Linux 系统编程 学习:11-线程:线程同步 背景 上一讲 我们介绍了线程的属性 有关设置。这一讲我们来看线程之间是如何同步的。 额外安装有关的man手册: sudo apt-get install manpages-posix-dev -y 情景导入 我们都知道引入线程在合理的范围内可以加快提高程序的效率。但我们先来看看如果多线程同时访问一个临...

2019年北航OO第二单元(多线程电梯任务)总结

一、三次作业总结 1. 说在前面 对于这次的这三次电梯作业,我采用了和几乎所有人都不同的架构:将每个人当作一个线程。这样做有一定的好处:它使得整个问题的建模更加自然,并且在后期人员调度变得复杂时,可以将调度器上纷繁的逻辑判断分布在不同的人身上,大大简化了代码逻辑。对于程序复杂度,将人作为某个容器中的PersonRequest时需要在电梯到达某一层时进行遍历...

Java线程并发中常见的锁--自旋锁 偏向锁

随着互联网的蓬勃发展,越来越多的互联网企业面临着用户量膨胀而带来的并发安全问题。本文着重介绍了在java并发中常见的几种锁机制。 1.偏向锁 偏向锁是JDK1.6提出来的一种锁优化的机制。其核心的思想是,如果程序没有竞争,则取消之前已经取得锁的线程同步操作。也就是说,若某一锁被线程获取后,便进入偏向模式,当线程再次请求这个锁时,就无需再进行相关的同步操作...

IO与线程状态

这几天在看IO和NIO, 说IO是阻塞的,当多个IO访问服务器时,发生阻塞的时候,CPU要不停的轮询每个IO的线程,看哪个IO的阻塞解除。会浪费CPU资源。 然后我看了线程的状态分类,专门有人说过阻塞和同步是不一样的。 1、新建状态(New):新创建了一个线程对象。 2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法...