admin

JAVA 多线程编程之 suspend、resume 废弃的原因
前言在较高的 JDK 版本中,我们可以看到Thread类中的suspend与resume方法都被加上了Deprec...
扫描右侧二维码阅读全文
22
2018/03

JAVA 多线程编程之 suspend、resume 废弃的原因

前言

在较高的 JDK 版本中,我们可以看到Thread类中的suspendresume方法都被加上了Deprecated注解,这意味着告诉我们不再建议使用这两个方法了,之所以不建议使用,原因有二:

  • 独占资源锁
  • 数据不同步

举例说明

首先来分析下出现死锁的情况,也就是独占资源锁:

public class SuspendResumeTest {

    static class MyThread extends Thread {
        private long i = 0;
        @Override
        public void run() {
            while (true) {
                i++;
                System.out.println(i);
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        myThread.start();
        Thread.sleep(1000);
        myThread.suspend();
        System.out.println("main end!");
    }
}

试猜想下程序最后会输出main end!吗?
答案是:不会。这就是 suspend、resume 使用不当可能会出现的问题,下面解释下为什么。
大家都知道 suspend 是暂停线程的意思,按道理执行完 suspend 会继续执行后面的代码,但是这里却阻塞了,关键还是得看 System.out.println 这个方法:

public void println(String x) {
    synchronized (this) {
        print(x);
        newLine();
    }
}

看到没有,里面有个监视器synchronized对代码块进行了同步,当线程代码在执行到这个同步代码块里面未退出之前,调用suspend方法的话,将会把线程暂停,并且锁得不到释放,所以后面的main end!输出代码将会被阻塞,导致死锁。

再来看看什么时候会出现数据不同步。

public class SuspendResumeTest {

    static class User {
        private String username = "default username";
        private String password = "default password";

        public void setValue(String username, String password) {
            this.username = username;
            if (Thread.currentThread().getName().equals("1")) {
                System.out.println("暂停1线程");
                Thread.currentThread().suspend();
            }
            this.password = password;
        }

        public void print() {
            System.out.println(username + ", " + password);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        final User user = new User();
        Thread t1 = new Thread() {
            @Override
            public void run() {
                user.setValue("zero", "new password");
            }
        };
        t1.setName("1");
        t1.start();
        Thread.sleep(1000);
        user.print();
    }
}

还是老样子,想象一下最终输出结果。
结果如下:

暂停1线程

zero, default password

这个程序只是用来说明suspend使用不当会出现这种数据不同步的问题,或许你会说你不会写出上面那样的傻逼代码,那如果是下面这种呢:

public class SuspendResumeTest {

    static class User {
        private String username = "default username";
        private String password = "default password";

        public void setValue(String username, String password) {
            this.username = username;
            try {
                //模拟一个耗时操作
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.password = password;
        }

        public void print() {
            System.out.println(username + ", " + password);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        final User user = new User();
        Thread t1 = new Thread() {
            @Override
            public void run() {
                user.setValue("zero", "new password");
            }
        };
        t1.setName("1");
        t1.start();
        Thread.sleep(1000);
        t1.suspend();
        user.print();
    }
}

结果和第一种差不多,数据未能同步。所以在程序中使用suspend方法要格外注意。
这里其实并未对resume为什么被废弃作出解释,因为suspendresume正确使用方法总是成对使用的,suspend都被废弃了,那么resume也就没有了存在的必要。

Last modification:March 22nd, 2018 at 06:01 pm
If you think my article is useful to you, please feel free to appreciate

Leave a Comment