先来看下结论:正确启动线程的方式是使用start()方法,而不是使用run()方法。html
“Talk is cheap. Show me the code”,用代码说话:分别调用run()方法和start()方法,打印输出线程的名字。安全
public class StartAndRunThread { public static void main(String[] args) { Runnable runnable = new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } }; runnable.run(); new Thread(runnable).start(); } }
运行结果:
并发
若是代码是这样的,执行结果有什么不一样呢?ide
public class StartAndRunThread { public static void main(String[] args) { Runnable runnable = new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } }; runnable.run(); new Thread(runnable).start(); runnable.run(); } }
执行结果为:
源码分析
是否是有点意外?然而,这就是真相。其实也不难解释。this
咱们说的并发是什么,并发不就是线程之间的运行互不干扰嘛?当JVM启动的时候,建立一个mian线程来运行main()方法。当执行到“new Thread(runnable).start();”的时候main线程会新建一个Thread-0线程。main线程和Thread-0线程的执行时互不相干的,因此可能不会出现“main-Thread-0-main”的结果。操作系统
我执行了n(n>20)次,运行结果依然如上图所示,没有出现“main-Thread-0-main”。这是为何呢?回忆一下线程的生命周期, Java中,线程(Thread)定义了6种状态: NEW(新建)、RUNNABLE(可执行)、BLOCKED(阻塞)、WAITING(等待)、TIMED_WAITING(限时等待)、TERMINATED(结束)。当调用了start()方法以后,线程进入RUNNABLE状态,RUNNABLE的意思是可运行,便可能正在执行,也可能没有正在执行。那调用了start方法以后,何时执行呢?调用start()方法以后,咱们只是告诉JVM去执行这个线程,至于何时运行是由线程调度器来决定的。从操做系统层面,其实调用start()方法以后要去获取操做系统的时间片,获取到才会执行。这个问题,能够对比思考“ thread.start()调用以后线程会马上执行吗?”更多能够参考:从源码解读线程(Thread)和线程池(ThreadPoolExecutor)的状态线程
start()源码以下:rest
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 */ } } }
能够看到,start()方法被synchronized关键字修饰,保证了线程安全。启动流程分为下面三个步骤:code
首先会检查线程状态,只有threadStatus == 0(也就是线程处于NEW状态)状态下的线程才能继续,不然会抛出IllegalThreadStateException。
将线程加入线程组
调用native方法——start0()方法启动线程。
会抛出IllegalThreadStateException,具体缘由能够用源码和线程启动步骤进行说明。
start()才是真正启动一个线程,而若是直接调用run(),那么run()只是一个普通的方法而已,和线程的生命周期没有任何关系。用代码验证一下:
public class Main implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName()); } public static void main(String[] args) { new Main().run(); new Thread(new Main()).start(); } }
在上面代码中,直接调用run()方法,run()只是一个普通的方法,由当前线程——main线程执行。start()才是真正启动一个线程——Thread0,run()方法由线程Thread0执行。
能够看start()方法的注释部分:
/** * Causes this thread to begin execution; the Java Virtual Machine * calls the <code>run</code> method of this thread. * <p> * The result is that two threads are running concurrently: the * current thread (which returns from the call to the * <code>start</code> method) and the other thread (which executes its * <code>run</code> method). * <p> * It is never legal to start a thread more than once. * In particular, a thread may not be restarted once it has completed * execution. * * @exception IllegalThreadStateException if the thread was already * started. * @see #run() * @see #stop() */
也就是说当该线程开始执行的时候,Java虚拟机会自动调用该线程的run()方法。