線程啟動和創建
創建和啟動線程
在java中創建一個線程如下:
Thread thread = new Thread();
調用方法start()來啟動一個線程:
thread.start();
這個例子沒有指定線程執行任何代碼,線程將會在啟動之後停止。
有兩種方式指定線程應該執行什麽代碼。第一種方式就是創建一個Thread的子類並覆寫run()方法。第二種方式就是創建一個實現Runnable接口的類。
Thread的子類
第一種方式指定線程執行什麽樣的代碼,就是創建一個Thread的子類,並且覆寫run()方法。在run()方法裏的代碼就是你調用start()方法後,線程要執行的代碼。下面是一個創建Thread子類的例子:
public class MyThread extends Thread{
@Override
public void run(){
System.out.println("MyThread running");
}
}
為了創建並啟動上面的線程,你應該這樣做:
MyThread myThread = new MyThread();
myThread.start();
start()方法會在線程開始後立馬返回,而不是等到run()方法執行完畢。當run()執行時,就會輸出“MyThread running”;
當然,你也可以創建一個Thread的匿名子類,如下:
Thread thread = new Thread(){
@Override
public void run(){
System.out.println("Thread Running");
}
}
thread.start();
上面的例子當線程被調用時會輸出文本“Thread Running".
實現Runnable接口
第二種方式指定線程應該執行什麽樣的代碼,就是創建一個實現java.lang.Runnable接口的類。這個Runnable對象可以被Thread執行。
下面是一個實現了Runnable接口的例子:
public class MyRunnable implements Runnable{
@Override
public void run(){
System.out.println("MyRunnable running");
}
}
因為有了Thread線程執行的run()方法,將MyRunnable的一個實例傳給Thread的構造方法。
Thread thread = new Thread(new MyRunnable());
thread.start();
當線程啟動時,會調用MyRunnable實例中的run()方法,而不是Thread自己的run()方法。上面的例子會輸出”MyRunnable running".
當然,你也可以創建一個匿名的Runnable接口實例:
Runnable myRunnable = new Runnable(){
@Override
public void run(){
System.out.println("Runnable running");
}
}
Thread thread = new Thread(myRunnable);
thread.start();
Subclass or Runnable?
沒有明確的規則說這兩種方式哪一種是最好的。個人傾向於實現Runnable接口。將實現Runable接口的一個實例交給Thread的實例。當由線程池來執行實現Runnable接口的線程實例時,當線程池沒有空閑線程可以調試時,可以讓這些線程很好的排隊。但是如果執行的是實現Thread的子類的線程實例,那麽將會很難做到這一點。
有時,你可能要同時實現Runnable和Thread子類。例如:創建一個Thread的線程可以執行一個或多個Runable實例,這就是線程池的實現方式。
常見的陷阱:調用run()方法而不是start()方法
當創建和啟動一個線程,通常會犯的一個錯誤就是調用run()方法,而不是start()方法,如下:
Thread newThread = new Thread(MyRunnable());
newThread.run(); // should be start();
起初,你可能沒有註意到什麽,因為run()正如你期待的那樣被執行了。然而,他並不是被你剛創建的線程所執行。而是被創建線程的線程執行。換句話說,就是執行上面兩行代碼的線程來執行的run()裏的方法。調用線程的使用start()方法。
線程名稱
當你創建一個線程時,你可以給這個線程指定名稱。線程名可以讓你和其他的線程進行區分。舉個例子:
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"作為一個參數傳給Thread的構造器,這個字符串就是線程的名稱,這個名稱可以通過方法getName()來獲取到,你也可以傳遞參數的方式給一個實現Runnable的接口的線程指定線程名稱:如下
MyRunnable runnable = new MyRunnable();
Thread thread = new Thread(runnable,"New Thread");
thread.start();
System.out.println(thread.getName());
註意。MyRunnable不是Thread的一個子類,他不能直接調用Thread的getName()方法。
Thread.currentThread()
Thread.currentThread()方法返回線程正在執行的線程。
Thread thread = Thread.currentThread();
只要獲取到當前運行線程,你就可以在此基礎上進行方法的調用。例如:你可以獲取到當前正在執行線程的名稱。
String threadName = Thread.currentThread().getName();
Java Thread example
這裏有一個小例子。首先輸出執行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並不是第一個執行的線程,這是因為線程的執行原則是並行的,而不是有序的,JVM和操作系統決線程的調度順序。當他們調度時順序是不固定的。
線程啟動和創建