原文鏈接:http://tutorials.jenkov.com/java-concurrency/creating-and-starting-threads.html
摘要:這是翻譯自一個大概30個小節的關於Java併發編程的入門級教程,原作者Jakob Jenkov,譯者Zhenning Lang,轉載請註明出處,thanks and have a good time here~~~(希望自己不要留坑)
Java 線程如 Java 中其他對象一樣也是一個對象。線程是 java.lang.Thread 的實例,或者是其子類的實例,Java 線程用來執行代碼。
1 Java 線程視頻教程
下面的鏈接是一個 Java 線程的視頻教程
https://www.youtube.com/embed/9y7l6QHpoQI
2 創建並啓動線程
Java 中像這樣創建一個線程:
Thread thread = new Thread();
爲了使這個線程啓動,需要調用其 start() 方法,
thread.start();
上面的例子沒有指定這個線程需要執行的代碼,所以這個線程將在啓動後立刻結束。
有兩種方法來指定線程需要執行的代碼。第一種是創建 Thread 的子類並覆蓋其 run() 方法,第二種方法是向 Thread 的構造函數傳遞一個實現了 Runnable(java.lang.Runnable) 接口的對象,下面將分別予以介紹。
2.1 創建Thread 的子類
第一種指定線程執行代碼的方法是創建一個 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();
2.2 實現 Runnable 接口
第二種指定多線程執行代碼的方法是創建一個實現 java.lang.Runnable 接口的類。Runnable 對象可以被線程執行。下面是一個簡單示例:
public class MyRunnable implements Runnable {
public void run(){
System.out.println("MyRunnable running");
}
}
爲了讓 run() 方法中的代碼被線程執行,需要將 MyRunnable 類的實例傳給 Thread 的構造函數,如下所示:
Thread thread = new Thread(new MyRunnable());
thread.start();
當 thread 啓動時,它會調用 MyRunnable 類的實例的 run() 方法,而不是其自己的 run() 反覆。上例會打印“MyRunnable running”。
也可以以匿名內部類的方式實現 Runnable 接口,如下所示:
Runnable myRunnable = new Runnable(){
public void run(){
System.out.println("Runnable running");
}
}
Thread thread = new Thread(myRunnable);
thread.start();
3 常見錯誤:錯把 run() 方法當做 start() 方法
當創建和啓動新線程時一個常見的錯誤是調用 run() 方法來啓動線程,而沒有調用 start() 方法,如下:
Thread newThread = new Thread(MyRunnable());
newThread.run(); //should be start();
雖然一開始一切看起來都很正常,運行結果也符合你的預期,但代碼並沒有在新線程中執行,而是在創建新線程的線程中被執行了。換言之就是沒有創建新的線程。
4 線程名
當你創建一個 Java 線程時你可以給其取一個名字,用於幫助你區分不同的線程。舉例來說,如果多個線程都調用 System.out,那麼很難判斷究竟是哪個線程進行了輸出。下面是給線程指定名稱的例子:
Thread thread = new Thread("New Thread") {
public void run(){
System.out.println("run by: " + getName());
}
};
thread.start();
System.out.println(thread.getName());
上面傳給 Thread 構造函數的字符串“New Thread”就是線程的名字。這個名字可以通過 Thread 類的 getName() 方法來獲得。實現 Runnable 接口的方式下給線程賦名字的示例如下:
MyRunnable runnable = new MyRunnable();
Thread thread = new Thread(runnable, "New Thread");
thread.start();
System.out.println(thread.getName());
這裏需要注意的是,由於 MyRunnable 類並不是 Thread 的子類,所以 MyRunnable 類內的 run() 方法並不能調用 getName() 方法(當然,可以通過 Thread.currentThread().getName() 實現這個功能)。
5 Thread.currentThread()
Thread.currentThread() 方法返回執行 Thread.currentThread() 函數的線程的實例引用。通過這種方法可以在代碼中獲得當前線程的 Thread 對象,如下例所示:
Thread thread = Thread.currentThread();
一旦獲得了 Thread 對象的引用,就可以調用其中的方法。下例展示瞭如何獲得當前線程的名稱:
String threadName = Thread.currentThread().getName();
6 實例
下面是一個實例。首先打印出 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 和/或者操作系統將決定線程的執行順序。