與執行緒的再次邂逅——建立執行緒
以前在學習執行緒時只用過一種建立方式,由於面試常問,現在來熟悉下建立執行緒的三種方式(其實是有四種,這裡只介紹3種)。
一.繼承Thread類
1.首先線上程實現類中繼承Thread類,使執行緒實現類成為Thread的子類。然後重寫Thread類中的run方法,run方法實際上就是執行體,方法中的程式碼實現就是執行緒所要完成的任務。
2.建立子類的物件,實際上也就是建立了Thread類的物件。
3.通過物件呼叫Thread類中的run方法,啟動執行緒。
//繼承Thread public class Demo extends Thread{ //執行體 public void run(){ //重寫run方法 System.out.println("執行重寫之後的run方法"); } public static void main(String[] args) { // TODO Auto-generated method stub //建立並啟動執行緒 Demo demo=new Demo(); demo.start(); } }
二.繼承Runnable介面
1.在介面實現類中繼承Runnable介面,重寫Runnable介面中的run方法,這時的run方法也是執行體。
2.建立Runnable實現類的例項物件,這時的物件並不是真正的執行緒物件,所以要把這時的物件傳給Thread來建立物件,這時的Thread物件才是真正的執行緒物件。
3.通過Thread物件呼叫run方法啟動執行緒。
//繼承Runnable介面 public class Demo1 implements Runnable{ //重寫介面中的run方法 public void run(){ System.out.println("執行重寫之後的run方法"); } public static void main(String[] args) { // TODO Auto-generated method stub //建立實現介面類的物件 Demo1 demo1=new Demo1(); //建立Thread的物件,並分配新的Thread物件 Thread thread=new Thread(demo1); //呼叫Thread裡面的start方法啟動執行緒 thread.start(); } }
三.繼承callable介面和利用Future介面實現
這種實現方式與前兩種相比,執行體發生了改變,但顯得比前兩種更為強大,該方式的執行體為Callable介面中的call方法,此方法可以有返回值,並且可以利用Future介面中的get方法接收執行緒結束之後的返回值,並且Future介面有一實現類Futuretask,這個實現類既繼承了Future介面,又繼承了Runnable介面,因此該類的物件可以作為Thread物件的target來建立Thread物件.(下面以返回值型別為int型為例)
1.在介面實現類中繼承Callable介面,重寫介面中的call方法,這時call方法才是執行緒的執行體,並且有返回值。
2.建立介面實現類的物件,並且將該物件傳遞給Futuretask類來建立Futuretask物件,再講Futuretask物件傳遞給Thread來建立Thread物件。
3.用Thread物件呼叫start方法啟動執行緒。
4.線上程結束之後,利用Futuretask物件呼叫get方法得到call方法的返回值(get方法需要丟擲異常)。
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
//使用Callable和Future實現
public class Demo2 implements Callable<Integer>{
public static void main(String[] args) throws InterruptedException, ExecutionException{
//例項化介面實現類的物件
Demo2 demo2=new Demo2();
//建立FutureTask物件封裝Demo2物件
FutureTask<Integer> future=new FutureTask<>(demo2);
//建立Thread類的物件封裝FutureTask物件
Thread thread =new Thread(future);
//啟動執行緒(呼叫了重寫之後的call方法)
thread.start();
//獲得call方法的返回值
int c=future.get();
System.out.println("c= "+c);
}
@Override
//執行體
public Integer call() throws Exception {
// TODO Auto-generated method stub
System.out.println("呼叫了重寫之後的call方法");
int a=3;
return a;
}
}
小結:
1.三種方式相比,不太建議使用第一種,因為java中是隻能繼承單個類的(除Object外),如果繼承了Thread類就無法繼承其他的類,所以就顯得這種方式比較笨拙。而介面是可以多繼承的,所以建議一般使用繼承介面來實現執行緒。
2.實現Runnable和Callable方式基本相同,但不同的是二者的執行體,後者的執行體有返回值。