Java——實現Java多執行緒的三種方法
Java虛擬機器允許應用程式併發地執行多個執行緒。在Java語言中,多執行緒的實現一般有以下3種方法,其中前兩種是最常用的方法。
1.繼承Thread類,重寫run()方法
Thread本質上也是實現了Runnable介面的一個例項,它代表一個執行緒的例項。並且,啟動執行緒的唯一方法就是通過Thread類的start()方法。
start()方法是一個native(本地)方法,它將啟動一個新執行緒,並執行run()方法(Thread中提供的run()方法是一個空方法)。這種方式通過自定義直接extend Thread,並重寫run()方法,就可以啟動新執行緒並執行自己定義的run()方法,需要注意的是,呼叫start()方法後不是立即執行多執行緒程式碼,而是使得該賢臣變為可執行態(Runnable),什麼時候執行多執行緒程式碼是由作業系統決定的。
Thread的使用方法:
class MyThread extends thread{//建立執行緒
public void run(){
System.out.println("Thread body");//執行緒的函式體
}
}
public class Test{
public static void main(String args[])
{
MyThread thread=new Mythread();
thread.start();//開啟執行緒
}
}
2.實現Runnable介面,並實現該介面的run()方法
如要步驟如下:
- 自定義類並實現Runnable介面,實現run()方法。
- 建立Thread物件,用事先Runnable介面的物件作為引數例項化該Thread物件。
- 呼叫Thread的start()方法。
示例如下:
class MyThread implements Runnable {//建立執行緒類 public void run(){ System.out.println("Thread body");//執行緒的函式體 } } public class Test{ public static void main(String args[]) { MyThread thread=new Mythread(); Thread t=new Thread(thread); t.start();//開啟執行緒 } }
從第一種方法和第二種方法的示例來看,我們可以發現,不管是通過繼承Thread類還是通過使用Runnable介面來實現多執行緒的方法,最終都還是通過Thread的物件的API來控制執行緒的。
引申:是否可以同時繼承Thread與實現Runnable介面?
當然可以啦。瞧本帥博主給你一個示例,你就知道啦~
public class Test extends Thread implements Runnable{
public static void main(String args[])
{
Thread t=new Thread(new Test());
t.start();
}
}
有些讀者看了這個例子,可能會懷疑這段程式沒有辦法編譯通過。因為從上面的例子中,我們可以看出,Test類實現了Runnable介面,但是並沒有實現介面的run()方法,可能有些讀者會認為這會導致編譯錯誤,但實際上它是能夠編譯通過並執行的,因為Test類從Thread類中即成了run()方法,這個繼承的 run()方法可以被當做對Runnable介面的實現,因此這段程式碼能夠編譯通過。
那要是不想用從Thread類中繼承的方法,那該怎麼辦呢?好說,在Test類中重寫run()方法來實現Runnable介面中的run()方法就可以了,且看下面的示例:
public class Test extends Thread implements Runnable{
public void run() {
System.out.println("this is run()");
}
public static void main(String args[])
{
Thread t=new Thread(new Test());
t.start();
}
}
3.實現Callable介面,重寫call()方法
Callable介面實際上是屬於Exector框架中的功能類,Callable介面與Runnable介面的功能類似,但是提供了比Runnable更強大的功能,主要表現為以下三點:
- Callable可以在任務結束後提供一個返回值,Runnable無法提供這個功能。
- Callable中的call()方法可以丟擲異常,而Runnable的run()方法不可以丟擲異常。
- 執行Callable可以拿到一個Future物件,Future物件表示非同步計算的結果,它提供了檢查計算是否完成的方法。由於執行緒屬於非同步計算模型,因此無法從別的執行緒中得到函式的返回值。在這種情況下,就可以使用Future來監視目標執行緒呼叫call()方法的情況。當呼叫Future的get()方法以獲取結果的時候,當前執行緒就會阻塞,直到call()方法結束返回結果。
示例如下:
package javatest;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class CallableAndFuture {
//建立執行緒類
public static class CallableTest implements Callable<String>
{
@Override
public String call() throws Exception {
// TODO Auto-generated method stub
return "Hello World";
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
ExecutorService threadPool=Executors.newSingleThreadExecutor();
Future<String>future=threadPool.submit(new CallableTest());
try {
System.out.println("waiting thread to finish");
System.out.println(future.get());
}catch(Exception e){
e.printStackTrace();
}
}
}
執行結果如下:
4.總結
以上三種方式中,前兩種方式執行緒執行完之後都沒有返回值,只有最後一種是帶返回值的。當要實現多執行緒時,一般推薦實現Runnable介面的方式,其原因是:
- 首先,Thread類定義了多種方法可以被派生類使用或者重寫。但是隻有run()方法是必須被重寫的,在run()方法中實現了這個縣城的主要功能。這當然是實現Runnable介面所需的方法。
- 其次,很多Java開發人員認為,一個類僅在它們需要被加強或者修改時才會被繼承。因此,如果沒有必要重寫Thread累的其他方法,那麼通過繼承Thread的實現方式與實現Runnable介面的效果相同,在這種情況下,最好通過實現Runnable介面的方式來建立執行緒。
好啦,以上就是實現Java多執行緒的三種方法的相關總結,如果大家有什麼更具體的發現或者發現文中有描述錯誤的地方,歡迎留言評論,我們一起學習呀~~
Biu~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pia!