Java執行緒是一個類似其他任何物件的一個物件類型。執行緒是java.lang.Thread類別的實例,或是這個類別的子類別的實例。除了作為物件類型之外,java線程也可以執行程式碼。
建立並啟動一個執行緒
建立一個執行緒可以像下面這樣:
Thread thread = new Thread();
為了啟動Java線程,你需要呼叫start方法,像下面這樣:
thread.start();
這個範例沒有指定執行緒將要執行的任何程式碼。這個線程在它啟動之後將會立刻停止。
這裡有兩種方式去指定這個執行緒應該執行的什麼程式碼。第一個方法就是去建立一個執行緒的子類,然後重寫這個run()方法。第二個方法就是傳遞一個實作了Runnable介面的物件給Thread建構子。這兩種方法在下面都會提及。
線程子類別
第一種方式是指定一個執行緒將會執行什麼程式碼,是去建立一個執行緒的子類別並且覆蓋run()方法。這個run()方法就是在你呼叫start()方法之後被這個執行緒執行的。這裡有一個例子:
public class MyThread extends Thread { public void run(){ System.out.println("MyThread running"); } }
去建立以及啟動上面的線程,你可以像下面這樣:
MyThread myThread = new MyThread(); myTread.start();
只要線程一啟動,start()方法就會回傳。它不會等到run()方法結束的。這個run()方法將會被不同的CPU執行。當這個run()方法執行的時候,它將會印出來「MyThread running」文字內容。
你也可以像下面這樣建立一個執行緒的匿名的子類別:
Thread thread = new Thread(){ public void run(){ System.out.println("Thread Running"); } } thread.start();
這個範例的運行結果將會跟上面一樣。
Runnable介面實作
第二種方法去指定一個執行緒應該執行什麼程式碼是透過建立一個實作java.lang.Runnable接口的一個類別。這個Runnable物件可以被一個執行緒執行。
這裡有一個例子:
public class MyRunnable implements Runnable { public void run(){ System.out.println("MyRunnable running"); } }
為了讓run方法被一個執行緒執行,需要傳遞一個MyRunnable實例給一個執行緒的建構子。這裡有一個例子:
Thread thread = new Thread(new MyRunnable()); thread.start();
當這個執行緒啟動的時候,它將會呼叫MyRunnable的run方法來取代執行他自己的run方法。上面的範例將會列印文字「MyRunnable running」。
你也可以像下面這樣建立一個匿名的實作:
Runnable myRunnable = new Runnable(){ public void run(){ System.out.println("Runnable running"); } } Thread thread = new Thread(myRunnable); thread.start();
繼承Thread還是實作介面?
這裡沒有規則關於這兩個方法哪一個是最好的。兩種方式都能運作。但是,對我個人來說,我更願意實現Runnable接口,以及管理這個實現的實例為了一個Thread實例。當有一個被執行緒池執行的Runnable實作的時候,它是很簡單的去排隊等待Runnable實例直到來自池中的執行緒是空閒的。這個透過使用Thread子類別去實現有點困難。
通常你不只要實作Runnable,也要實作子類別Thread。例如,如果建立一個Thread子類別可以執行不只一個Runnable。這個就是典型的實作一個執行緒池的實例。
常見陷阱:呼叫run()取代start()
#當建立和啟動一個執行緒的時候,一個常見的錯誤就是調用Thread的run方法取代start方法,像下面這樣:
Thread newThread = new Thread(MyRunnable()); newThread.run(); //should be start();
首先你可能沒有註意到任何事情,因為Runnable的run方法也會像你所期望的會執行。然而,它不會被你創建的新線程執行。代替創建線程的那個線程的run方法被執行。換句話說,上面兩行程式碼執行的執行緒。為了使得新建立的線程的實例的run方法被調用,你必須調用start方法。
線程名稱
當你建立一個java執行緒的時候,你可以給他一個名字。這個名字可以幫助你區分不同的線。例如,如果多個執行緒寫這個輸出,它可以看出來哪個執行緒寫的哪個文字。這裡有一個例子:
Thread thread = new Thread("New Thread") { public void run(){ System.out.println("run by: " + getName()); } }; thread.start(); System.out.println(thread.getName());
注意傳遞給Thread建構子的這個字元竄參數。這個字串就是線程的名稱。這個名稱可以透過Thread的getName方法來取得。當執行一個Runnable實作的時候,也可以傳遞一個名稱。像下面這樣:
MyRunnable runnable = new MyRunnable(); Thread thread = new Thread(runnable, "New Thread"); thread.start(); System.out.println(thread.getName());
然而要注意,因為MyRunnable類別不是Thread類別的子類,它不能存取正在執行它的執行緒的getName()方法。
Thread.currentThread()
這個方法傳回一個正在執行的目前執行緒的Thread實例的一個參考。這個方式你可以存取正在執行的程式碼區塊的執行緒的Thread物件。這裡有一個例子:
Thread thread = Thread.currentThread();
一旦你有一個Thread物件的一個引用,你可以呼叫關於它的方法了。例如,你可以取得執行的這個執行緒的名字:
String threadName = Thread.currentThread().getName();
Java執行緒實例
这里有一个小的例子。首先它打印出来了正在执行的main方法的线程的名字。这个线程是被JVM分配的。然后启动了10个线程,以及给予他们所有作为名称(“”+i)的一个数字。每一个线程然后打印出名字,以及停止执行。
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(); } } }
注意,甚至如果线程是按顺序启动的(1,2,3等等)。他们可能也不会按顺序执行的,意味着线程1可能不是第一个打印出来的名字。这个就是为什么原则上线程是并行运行而不是顺序呢执行的原因了。这个JVM以及操作系统决定着线程执行的顺序。这个顺序每次在他们启动的时候都不会相同的。
以上就是创建以及启动一个Java线程的内容,更多相关内容请关注PHP中文网(www.php.cn)!