利用notify和wait方法实现suspend和resume(附带jstack和jps查看线程运行状态)

suspend和resume的废除

查阅java api 可以发现suspend和resume已经被标注为废弃方法。原因其实也不是很复杂,因为suspend在导致线程暂停的同时不会去释放任何资源,直到在对应线程上执行了resume操作,被挂起的线程才能继续,从而其他所有阻塞在相关锁的线程也可以继续执行,但是,如果resume操作意外的在suspend操作前就执行了,那么被挂起的线程很难再去执行。

为了理解suspend的这个问题,可以参考下面这个代码demo

public class BadSuspend {
    public static Object u = new Object();
    static ChangeObjectThread t1= new ChangeObjectThread("t1");
    static ChangeObjectThread t2= new ChangeObjectThread("t2");

    public static class ChangeObjectThread extends Thread{
        public ChangeObjectThread(String name){
            super.setName(name);
        }
        @Override
        public void run(){
            synchronized(u){
                System.out.println("in "+getName());
                Thread.currentThread().suspend();
                //ide这里会将suspend方法画上斜线表明已经废弃使用了
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        t1.start();
        Thread.sleep(1000);
        t2.start();
        t1.resume();
        t2.resume();
        t1.join();
        t2.join();
    }
}

运行结果:

in t1
in t2

但是要注意一点,此时我们的程序并没有结束运行而是一直处于运行状态!!

现在我们可以借助jps和jstack工具来查看原因哦!

首先笔者用的系统是ubuntu18,当然Windows你就打开cmd就行。下面介绍ubuntu查看方式,windows cmd输入的一样。

打开终端,

输入jps

jet@jet-X555LF:~$ jps
9124 Launcher
9126 BadSuspend
2343 Main
9336 Jps
jet@jet-X555LF:~

找到对应的pid,这里的pid是9126

然后输入jstack 9126

找到这一行

"t2" #11 prio=5 os_prio=0 tid=0x00007f4004209000 nid=0x23cd runnable [0x00007f3ff071c000]
   java.lang.Thread.State: RUNNABLE
    at java.lang.Thread.suspend0(Native Method)
    at java.lang.Thread.suspend(Thread.java:1032)
    at BadSuspend$ChangeObjectThread.run(BadSuspend.java:14)
    - locked <0x00000000d70ad418> (a java.lang.Object)

这时要注意,当前线程t2是挂起的,但是它的线程状态确实是RUNNABLE,这很有可能使我们误判当前系统状态。同时,虽然主函数中已经调用了resume(),但是由于时间先后顺序的缘故,那个resume并没有生效。

wait()和notify()实现可靠的suspend和resume

public class GoodSuspend {
    public static Object u = new Object();

    public static class ChangeObjectThread extends Thread {
        volatile boolean suspendme = false;

        public void suspendMe() {
            suspendme = true;
        }

        public void resumeMe() {
            suspendme = false;
            synchronized (this) {
                notify();
            }
        }

        @Override
        public void run() {
            while (true) {
                synchronized (this) {
                    while (suspendme) {
                        try {
                            wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
                synchronized (u) {
                    System.out.println("in ChangeObjectThread");
                }
                Thread.yield();
            }
        }
    }
    public static class  ReadObjectThread extends Thread{
        @Override
        public void run(){
            while(true){
                synchronized (u){
                    System.out.println("in ReadObjectThread");
                }
                Thread.yield();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ChangeObjectThread t1 = new ChangeObjectThread();
        ReadObjectThread t2 = new ReadObjectThread();
        t1.start();
        t2.start();
        Thread.sleep(1000);
        t1.resumeMe();
        System.out.println("suspend t1 2 sec");
        Thread.sleep(2000);
        System.out.println("resume t1");
        t1.resumeMe();
    }
}

代码中,给出一个标记变量suspendme,表示当前线程是否被挂起。同时,增加了suspendMe()和resumeMe()两个方法,分别用于挂起线程和继续执行线程。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值