关于Thread的start和run方法的执行方式

今天突然想到,在主线程中启动一个子线程,在子线程执行完毕后,是否可以自动销毁的疑惑,带着问题,开始考虑编码,在编码过程中分别使用了Runnable和Thead两种不同的方式,下面先看第一中Runnable方式。

  1. Runnable方式
class RunnableTest implements Runnable {

    @Override
    public void run() {
        System.out.println("我是新启动的Runnable!");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在该方式中,先让子线程休眠2秒中(用于在主线程中持续查看当前所有线程时观察线程的变化),主线程调用如下:

public class ThreadDemo {
    public static void main(String[] arg) throws InterruptedException {
        RunnableTest().run();
        while (true){
            Thread[] threads = findAllThreads();
            for(Thread t : threads){
                System.out.println(t.getId()+":"+t.getName());
            }
            Thread.sleep(1000);
        }
    }

    /**
     * 用于获取当前JVM中所有的线程
     * @return
     */
    public static Thread[] findAllThreads() {
        ThreadGroup group = Thread.currentThread().getThreadGroup();
        ThreadGroup topGroup = group;
        // 遍历线程组树,获取根线程组
        while (group != null) {
            topGroup = group;
            group = group.getParent();
        }
        // 激活的线程数加倍
        int estimatedSize = topGroup.activeCount() * 2;
        Thread[] slacks = new Thread[estimatedSize];
        //获取根线程组的所有线程
        int actualSize = topGroup.enumerate(slacks);
        Thread[] threads = new Thread[actualSize];
        System.arraycopy(slacks, 0, threads, 0, actualSize);
        return threads;
    }
}

运行后发现一个问题,在调用RunnableTest().run()方法后,发现主线程被阻塞了,并没有立即执行后面的while循环体,结果先执行了子线程中的休眠,等休眠结束后,才执行主线程的后续代码,此时,输出的所有线程中没有子线程的影子,如下:
这里写图片描述
只有一些系统线程,可是说明时,子线程执行结束后,立马释放掉了,但问题来了,原本以为子线程的调用时异步的,不会阻塞主线程,但这里的效果是阻塞的,一时间有点不明所以,好吧,那使用Thread的方式看看效果。
2. Thread方式

class ThreadTest extends Thread{
    @Override
    public void run() {
        System.out.println("我是新启动的Thread!");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在主线程中调用new ThreadTest().start();这个时候发现,在调用后,立即执行主线程中的后续代码,并没有出现主线程阻塞的情况,而且在线程情况的输出中看到了子线程的影子,并且在子线程休眠结束后,子线程销毁掉了,运行结果如下:
这里写图片描述
可以看出,1,2时可以看到子线程的影子,在3处,由于子线程休眠结束,销毁掉了,所以没有子线程。同样可以说明,主线程中调用了子线程,子线程执行结束后,会立即销毁。但问题来了,使用Runnable.run()的方式为什么会出现阻塞主线程的情况,而Thread.start()的方式不阻塞呢?下面具体探讨下。


带着以上的疑问,将new ThreadTest().start();换成new ThreadTest().run();后,同样主线程出现阻塞,原来,不管是通过Runnable.run()还是Thread.run()运行,其实就是一个普通类方法的调用,当然时顺序调用的方式,而使用Thread.start()时,此时,子线程的具体执行则有系统来决定,异步执行,不阻塞主线程,至此,疑惑出现柳暗花明,哈哈,问题的发现到疑惑的解决,全是平时细节的马马虎虎,纯属庸人自扰了!

猜你喜欢

转载自blog.csdn.net/yuxiao97/article/details/80037780
今日推荐