Java线程系列——线程的启动

2020-02-21  本文已影响0人  禺沫

一、start和run的比较

先看一个简单的例子

public class StartAndRunMethod {
    public static void main(String[] args) {
        Runnable runnable = () -> {
            System.out.println(Thread.currentThread().getName());
        };
        runnable.run();
        new Thread(runnable).start();
    }
}

运行结果如下:
main
Thread-0
可见,运行run()方法还是在主线程中执行。并没有起到新启线程的目的。

二、start方法具体作用

那么运行start()方法,具体都做了什么呢?

  1. 通知JVM有空闲的时候启动新线程,等待线程调度器执行。不一定会马上执行,线程执行顺序也无法保证。
  2. start()方法会涉及到两个线程,主线程和子线程。子线程是需要先做一些准备工作才能运行的。比如,让自己处于就绪状态(获取到除了cpu以外的其他资源,比如设置了上下文,栈,线程状态,pc指向了程序运行的位置)。准备工作做完后,才会被JVM或者操作系统调度到运行状态,等待获取cpu资源,再到运行状态,运行run方法中的代码。可见,一个线程的执行,并不简单。

三、start方法的使用注意:

那么在调用start()方法时,应该注意些什么?

public class CantStartTwice {
    public static void main(String[] args) {
        Thread thread = new Thread();
        thread.start();
        thread.start();
    }
}

比如不小心运行了两次start(),运行结果如下:

Exception in thread "main" java.lang.IllegalThreadStateException
at java.lang.Thread.start(Thread.java:705)
at startthread.CantStartTwice.main(CantStartTwice.java:11)

出现了非法的线程状态异常。
其原因为,一旦开始执行就从最开始的new状态,到后续的状态,比如runnable状态。一旦线程执行完毕,就会变成终止状态,而终止状态永远不能返回回去,所以才会抛出这个异常。

四、start源码解析

在java.lang.Thread中,源码如下:

public synchronized void start() {
    /**
     * This method is not invoked for the main method thread or "system"
     * group threads created/set up by the VM. Any new functionality added
     * to this method in the future may have to also be added to the VM.
     *
     * A zero status value corresponds to state "NEW".
     */
    if (threadStatus != 0)
        throw new IllegalThreadStateException();

    /* Notify the group that this thread is about to be started
     * so that it can be added to the group's list of threads
     * and the group's unstarted count can be decremented. */
    group.add(this);

    boolean started = false;
    try {
        start0();
        started = true;
    } finally {
        try {
            if (!started) {
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {
            /* do nothing. If start0 threw a Throwable then
              it will be passed up the call stack */
        }
    }
}

private native void start0();

可知,start方法主要进行了如下逻辑:
1.启动新线程检查线程状态
2.加入线程组
3.调用start0()

上一篇 下一篇

猜你喜欢

热点阅读