Java建立執行緒的三種方式
Java建立執行緒的三種方式
一、直接使用Thread建立(繼承Thread類)
這種方式通過直接覆蓋Thread
類中的run
方法建立執行緒
- 繼承Thread類
- 首先建立一個類,
繼承
自Thread類 - 然後
重寫
Thread的run方法,方法裡面寫要併發執行的程式碼 - 在main方法裡面建立執行緒,使用
start
方法開啟執行緒。(注意:一定要使用start
而不是run方法開啟執行緒。如果直接呼叫run()方法,程式將執行完run()方法後才會執行main()方法中後面的程式碼,這樣就是單執行緒執行而不是多執行緒併發執行了)
//繼承Thread類
class MyThread extends Thread{
//重寫run方法
public void run() {
//t1執行緒
System.out.println(Thread.currentThread().getName() + " is running");
}
}
public class Test1 {
public static void main(String[] args) {
Thread t = new MyThread();
//設定執行緒名字
t.setName ("t1");
//開啟執行緒
t.start();
//主執行緒
System.out.println(Thread.currentThread().getName() + " is running");
}
}
列印結果:
可以看到是先執行了main執行緒裡面的 sout語句,然後才執行 t1執行緒的語句。說明是併發執行的。
-
直接重寫Thread方法
這種方式與上面建立的方式一樣,不過會簡潔一點。
public static void main(String[
二、 使用Runnable配合Thread
優點:
把執行緒
和任務
(要執行的程式碼)分開,通過組合而不是繼承的方式建立了執行緒。這讓程式碼更加的靈活,
Thread 代表執行緒
Runnable 代表任務
public static void main(String[] args) {
//建立一個任務
Runnable runnable = new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName() + " is running");
}
};
//使用Thread類,將runable作為引數建立執行緒
Thread t = new Thread(runnable , "t2");
//開啟執行緒
t.start();
System.out.println(Thread.currentThread().getName() + " is running");
}
結果:
-
小結
-
方法1 是把執行緒和任務合併在了一起,方法2 是把執行緒和任務分開了
-
用 Runnable 更容易與執行緒池等高階 API 配合
-
用 Runnable 讓任務類脫離了 Thread 繼承體系,更靈活。使用了組合的方式建立執行緒。
-
三、配合Callable介面和Future建立執行緒
這種方式可以獲得執行緒的返回值,FutureTask 能夠接收 Callable 型別的引數,用來處理有返回結果的情況
在使用這個方式建立執行緒之前,首先要明白FutureTask的繼承關係。可以看到FutureTask實現了RunnableFuture介面。而此介面又繼承了Runnable和Future介面。所以FutureTask實際上也是一個Runnable,它除了實現Runnable介面以外,還實現了Future介面。而獲得執行緒的返回值正是通過這個介面進行實現的。
-
首先要建立實現了Callable介面的實現類MyCallable,實現call方法。Callable介面是一個泛型介面,其型別就是返回值的型別。實現Callable介面中的call()方法,方法的返回型別與泛型的型別相同。
class MyCallable implements Callable<Integer>{ //重寫call 方法 public Integer call() throws Exception { System.out.println(Thread.currentThread().getName() + " is running"); //睡眠1s Thread.sleep(1000); //返回100 return 100; } }
-
Callable不能直接獲取返回值,需要用FutureTask在外部封裝一下再獲取返回值
在使用task.get() 方法獲取返回值時,是阻塞式的等待。上面callable介面在返回值之前睡眠了1s,則這個get方法就會阻塞式的等待1s
public static void main(String[] args) throws ExecutionException, InterruptedException { //建立Callable介面實現類 Callable callable = new MyCallable(); //建立FutrueTask類 FutureTask<Integer> task = new FutureTask<>(callable); //建立執行緒,task實現了Runnable介面 Thread t = new Thread(task,"t1"); t.start(); //呼叫get方法獲取返回值 System.out.println(Thread.currentThread().getName() + " " + task.get()); }
-
結果
執行完執行緒t1,然後通過get方法獲得了返回值