準(zhǔn)確的講运杭,創(chuàng)建線程只有一種方式础倍,那就是構(gòu)造Thread類(lèi)飒硅,而實(shí)現(xiàn)線程的執(zhí)行單元(run()方法)有兩種方式
方法1:繼承Thread類(lèi)柄驻,重寫(xiě)Thread的run方法
方法2:實(shí)現(xiàn)Runnable接口的run方法狐树,并把Runnable實(shí)例傳給Thread類(lèi)
Oracle官方文檔說(shuō)明:
https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html
第一種(繼承Thread類(lèi))
public class ThreadStyle extends Thread {
public static void main(String[] args) {
new ThreadStyle().start();
}
@Override
public void run() {
System.out.println("繼承Thread方法");
}
}
第二種(實(shí)現(xiàn)Runnable接口)
public class RunnableStyle implements Runnable {
public static void main(String[] args) {
new Thread(new RunnableStyle()).start();
}
@Override
public void run() {
System.out.println("實(shí)現(xiàn)Runnable接口方法");
}
}
實(shí)現(xiàn)Runnable接口和繼承Thread類(lèi)哪種方式更好
- 從代碼架構(gòu)角度:
這里分為兩件事情焙压,第一件事情是具體的任務(wù)(也就是run()方法里的內(nèi)容)
第二件事情是跟整個(gè)線程生命周期相關(guān)的鸿脓,比如說(shuō)創(chuàng)建線程抑钟、運(yùn)行線程、銷(xiāo)毀線程等野哭,這個(gè)是Thread類(lèi)去做的事情在塔。
這兩個(gè)事情目的不一樣,所以從代碼架構(gòu)角度應(yīng)該是解耦的拨黔,所以實(shí)現(xiàn)Runnable接口更好 - 新建線程的損耗:
繼承Thread類(lèi)蛔溃,每次想新建任務(wù),只能去新建一個(gè)獨(dú)立的線程篱蝇,而新建獨(dú)立線程損耗是比較大的贺待;使用Runnable可以使用線程池等工具,利用工具就能減少創(chuàng)建線程零截、銷(xiāo)毀線程帶來(lái)的損耗麸塞。 - 對(duì)于擴(kuò)展性而言,Java不支持雙繼承
綜上所述:實(shí)現(xiàn)Runnable接口比繼承Thread類(lèi)更好
兩種方法的本質(zhì)對(duì)比
Thread類(lèi)中run()方法源碼
public class Thread implements Runnable {
……
……
此處省略
/* What will be run. */
private Runnable target;
……
/**
* 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();
}
}
...
...
...
}
- 方法1(繼承Thread類(lèi))run()方法整個(gè)都被重寫(xiě)涧衙;
- 方法2(實(shí)現(xiàn)Runnable接口)傳遞進(jìn)來(lái)一個(gè)target(target就是Runnable對(duì)象)哪工,判斷target不為null,最后調(diào)用target.run();
- 本質(zhì)上兩種方法最后都是調(diào)用run()方法弧哎。
如果同時(shí)使用兩種方法啟動(dòng)線程雁比?
public class BothRunnableThread {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("我來(lái)自Runnable");
}
}) {
@Override
public void run() {
System.out.println("我來(lái)自Thread");
}
}.start();
}
}
控制臺(tái)會(huì)打印什么?
運(yùn)行結(jié)果:
我來(lái)自Thread
為什么“我來(lái)自Runnable”沒(méi)有輸出撤嫩?
因?yàn)閚ew Thread創(chuàng)建了一個(gè)匿名內(nèi)部類(lèi)偎捎,傳入了一個(gè)Runnable對(duì)象,
new Runnable() {
@Override
public void run() {
System.out.println("我來(lái)自Runnable");
}
}
之后又重寫(xiě)了run()方法序攘,
@Override
public void run() {
System.out.println("我來(lái)自Thread");
}
最后調(diào)用start()去運(yùn)行鸭限,
但是重寫(xiě)了run()方法,導(dǎo)致下面3行代碼也沒(méi)了两踏,
if (target != null) {
target.run();
}
所以即便是傳入了Runnable對(duì)象败京,它的target.run();也不會(huì)執(zhí)行