Java 并發(fā)/多線程教程(七)-創(chuàng)建和啟動(dòng)java線程

? ? ? 本系列譯自jakob jenkov的Java并發(fā)多線程教程,個(gè)人覺(jué)得很有收獲。由于個(gè)人水平有限,不對(duì)之處還望矯正!

創(chuàng)建和啟動(dòng)線程

在java中創(chuàng)建一個(gè)線程如下:

Thread thread = new Thread();

調(diào)用方法start()來(lái)啟動(dòng)一個(gè)線程:

thread.start();

? ? ? ? 這個(gè)例子沒(méi)有指定線程執(zhí)行任何代碼,線程將會(huì)在啟動(dòng)之后停止。

? ? ? ? 有兩種方式指定線程應(yīng)該執(zhí)行什么代碼。第一種方式就是創(chuàng)建一個(gè)Thread的子類并覆寫(xiě)run()方法。第二種方式就是創(chuàng)建一個(gè)實(shí)現(xiàn)Runnable接口的類。

Thread的子類

? ? ? 第一種方式指定線程執(zhí)行什么樣的代碼,就是創(chuàng)建一個(gè)Thread的子類,并且覆寫(xiě)run()方法。在run()方法里的代碼就是你調(diào)用start()方法后,線程要執(zhí)行的代碼。下面是一個(gè)創(chuàng)建Thread子類的例子:

public class MyThread extends Thread{

? ? ? ?@Override

? ? ? ? public void run(){

? ? ? ? ? ? ?System.out.println("MyThread running");

? ? ? ? }

}

為了創(chuàng)建并啟動(dòng)上面的線程,你應(yīng)該這樣做:

MyThread myThread = new MyThread();

myThread.start();

start()方法會(huì)在線程開(kāi)始后立馬返回,而不是等到run()方法執(zhí)行完畢。當(dāng)run()執(zhí)行時(shí),就會(huì)輸出“MyThread running”;

當(dāng)然,你也可以創(chuàng)建一個(gè)Thread的匿名子類,如下:

Thread thread = new Thread(){

? ? ? @Override

? ? ? ?public void run(){

? ? ? ? ? ? ? ? System.out.println("Thread Running");

? ? ? ?}

}

thread.start();

上面的例子當(dāng)線程被調(diào)用時(shí)會(huì)輸出文本“Thread Running".

實(shí)現(xiàn)Runnable接口

? ? ?第二種方式指定線程應(yīng)該執(zhí)行什么樣的代碼,就是創(chuàng)建一個(gè)實(shí)現(xiàn)java.lang.Runnable接口的類。這個(gè)Runnable對(duì)象可以被Thread執(zhí)行。

? ? ?下面是一個(gè)實(shí)現(xiàn)了Runnable接口的例子:

public class MyRunnable implements Runnable{

? ? ? @Override

? ? ? public void run(){

? ? ? ? ? ? System.out.println("MyRunnable running");

? ? ? }

}

因?yàn)橛辛薚hread線程執(zhí)行的run()方法,將MyRunnable的一個(gè)實(shí)例傳給Thread的構(gòu)造方法。

Thread thread = new Thread(new MyRunnable());

thread.start();

? ? 當(dāng)線程啟動(dòng)時(shí),會(huì)調(diào)用MyRunnable實(shí)例中的run()方法,而不是Thread自己的run()方法。上面的例子會(huì)輸出”MyRunnable running".

當(dāng)然,你也可以創(chuàng)建一個(gè)匿名的Runnable接口實(shí)例:

Runnable myRunnable = new Runnable(){

? ? ? ? @Override

? ? ? ? public void run(){

? ? ? ? ? ? ? ?System.out.println("Runnable running");

? ? ? ? ?}

}

Thread thread = new Thread(myRunnable);

thread.start();

Subclass or Runnable?

? ? ? ?沒(méi)有明確的規(guī)則說(shuō)這兩種方式哪一種是最好的。個(gè)人傾向于實(shí)現(xiàn)Runnable接口。將實(shí)現(xiàn)Runable接口的一個(gè)實(shí)例交給Thread的實(shí)例。當(dāng)由線程池來(lái)執(zhí)行實(shí)現(xiàn)Runnable接口的線程實(shí)例時(shí),當(dāng)線程池沒(méi)有空閑線程可以調(diào)試時(shí),可以讓這些線程很好的排隊(duì)。但是如果執(zhí)行的是實(shí)現(xiàn)Thread的子類的線程實(shí)例,那么將會(huì)很難做到這一點(diǎn)。

? ? ? ?有時(shí),你可能要同時(shí)實(shí)現(xiàn)Runnable和Thread子類。例如:創(chuàng)建一個(gè)Thread的線程可以執(zhí)行一個(gè)或多個(gè)Runable實(shí)例,這就是線程池的實(shí)現(xiàn)方式。

常見(jiàn)的陷阱:調(diào)用run()方法而不是start()方法

? ? ? 當(dāng)創(chuàng)建和啟動(dòng)一個(gè)線程,通常會(huì)犯的一個(gè)錯(cuò)誤就是調(diào)用run()方法,而不是start()方法,如下:

Thread newThread = new Thread(MyRunnable());

newThread.run(); // should be start();

起初,你可能沒(méi)有注意到什么,因?yàn)閞un()正如你期待的那樣被執(zhí)行了。然而,他并不是被你剛創(chuàng)建的線程所執(zhí)行。而是被創(chuàng)建線程的線程執(zhí)行。換句話說(shuō),就是執(zhí)行上面兩行代碼的線程來(lái)執(zhí)行的run()里的方法。調(diào)用線程的使用start()方法。

線程名稱

? ? ? ?當(dāng)你創(chuàng)建一個(gè)線程時(shí),你可以給這個(gè)線程指定名稱。線程名可以讓你和其他的線程進(jìn)行區(qū)分。舉個(gè)例子:

Thread thread = new Thread("New Thread"){

? ? ? ?@override

? ? ? ?public void run(){

? ? ? ? ? ? ? System.out.println("run by:"+getName());

? ? ? }

}

thread.start();

System.out.println(thread.getName());

注意,字符串“New Thread"作為一個(gè)參數(shù)傳給Thread的構(gòu)造器,這個(gè)字符串就是線程的名稱,這個(gè)名稱可以通過(guò)方法getName()來(lái)獲取到,你也可以傳遞參數(shù)的方式給一個(gè)實(shí)現(xiàn)Runnable的接口的線程指定線程名稱:如下

MyRunnable runnable = new MyRunnable();

Thread thread = new Thread(runnable,"New Thread");

thread.start();

System.out.println(thread.getName());

注意。MyRunnable不是Thread的一個(gè)子類,他不能直接調(diào)用Thread的getName()方法。

Thread.currentThread()

Thread.currentThread()方法返回線程正在執(zhí)行的線程。

Thread thread = Thread.currentThread();

只要獲取到當(dāng)前運(yùn)行線程,你就可以在此基礎(chǔ)上進(jìn)行方法的調(diào)用。例如:你可以獲取到當(dāng)前正在執(zhí)行線程的名稱。

String threadName = Thread.currentThread().getName();

Java Thread example

這里有一個(gè)小例子。首先輸出執(zhí)行main方法的線程名稱。這個(gè)線程是由JVM指定的。然后開(kāi)啟10個(gè)線程,并以”“+i作為他們的線程名。每個(gè)線程輸出他們的名字后,然后停止。

public class ThreadExample{

? ? ?public static void main(String[] args){

? ? ? ? ? ?System.out.println(Thread.currentThread().getName());

? ? ? ? ? ?for(int i=0;i<10;i++){

? ? ? ? ? ? ? new Thread(""+i){

? ? ? ? ? ? ? ? ? ?public void run(){

? ? ? ? ? ? ? ? ? ? ? ?System.out.println("Thread:"+getName()+"running");

? ? ? ? ? ? ? ? ? ?}

? ? ? ? ? ? ?}.start();

? ? ? ? ?}

? ? ? }

}

注意。線程并不是有序執(zhí)行的。也就是說(shuō)線程1并不是第一個(gè)執(zhí)行的線程,這是因?yàn)榫€程的執(zhí)行原則是并行的,而不是有序的,JVM和操作系統(tǒng)決線程的調(diào)度順序。當(dāng)他們調(diào)度時(shí)順序是不固定的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容