java Thread中的start()和run()
有什么不同之处,需要注意些什么?
一、实际效果
(1)上代码
test.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
package com.xie.testThread; import java.util.concurrent.atomic.AtomicInteger; public class test implements Runnable { private static AtomicInteger incrementId = new AtomicInteger(0); public static int getincrementId() { return incrementId.incrementAndGet(); } public void run() { // TODO Auto-generated method stub int id = 0; while ((id = getincrementId()) <= 1000) { System.out.println("当前线程" + Thread.currentThread().getName() + ",id=" + id); try { Thread.sleep(50); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static void main(String[] args) { System.out.println("start"); for (int i = 1; i <= 10; i++) { Thread thread = new Thread(new test()); thread.setName("线程" + i); thread.start(); } System.out.println("end"); } } |
如果使用:
1 |
thread.start() |
可以正常使用多线程处理run方法。
但是如果使用:
1 |
thread.run() |
就会发现所有的run方法都是在main线程中进行处理的,根本没有使用多线程。
(2)结论
参考:http://blog.csdn.net/xuxurui007/article/details/7685076
(1)使用start()方法启动线程,才是真正实现了多线程运行
无需等待run方法体代码执行完毕,不会被阻塞,可以直接继续执行下面的代码。
如果通过调用Thread类的start()方法来启动一个线程,此线程是处于就绪状态,并没有运行。启动线程红,Thread类会自动调用run()来完成线程的运行操作,这里的方法run()被称为线程体,它包含了要执行的这个线程的内容。run方法运行结束后,此线程将终止。然后CPU再调度其它线程。
(“然后CPU再调度其它线程”的说法可能有误。run运行时线程可以主动把CPU资源出让)
(2)run()方法当作普通方法的方式调用,程序还是要同步执行
等待run方法体执行完毕后,才可继续执行下面的代码。
程序中只有主线程这唯一的线程,没有达到多线程的效果。
二、看看源码
(1)Runnable接口
1 |
public abstract void run(); |
因为Thread类实现了Runnable接口,所以肯定要实现这个run方法,就是Thread.run()。
(2)Thread类
1.看看run方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/** * If this thread was constructed using a separate * <code>Runnable</code> run object, then that * <code>Runnable</code> object's <code>run</code> method is called; * otherwise, this method does nothing and returns. * <p> * Subclasses of <code>Thread</code> should override this method. * * @see #start() * @see #stop() * @see #Thread(ThreadGroup, Runnable, String) */ @Override public void run() { if (target != null) { target.run(); } } |
再看看这个target是什么:
1 2 |
/* What will be run. */ private Runnable target; |
发现target就是Runnable接口。
个人理解:如果我们重构了run方法,那么将执行我们重写的run方法。如果没有重写run方法,那就什么都不执行。
2.看看start方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
/** * 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() */ 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 */ } } } |
除了抛出很多错误以外,核心代码是这个start0():
1 |
private native void start0(); |
似乎很多资料都在说,start()实际上也是调用了run()。所以我就想看一下是不是实现在start0里面了。
但是在源码中我没有找到这个start0的实现。
(start0是private native void start0()方法,也就是jvm自己实现的原生方法(不仅限于使用c实现),想要看实现只能去看jvm的源码,在java代码中是找不到的)
后来查了一下,在下面的网站中有详细说明:
https://www.ibm.com/developerworks/cn/java/j-lo-processthread/
涉及到jvm和操作系统对多线程的底层实现。因为我暂时还不能理解,不继续深究。
(这有啥好看不懂的,懒就懒吧)
三、总结
总之,如果要并发,那么当然使用start()。如果要在当前线程上跑run方法,才直接调用run()(这种情况似乎比较少见)。