Java語言內置了多線程支持。當咱們啓動一個Java程序時,其實是啓動了一個JVM進程,而後JVM啓動主線程來執行main()
方法。在main()
方法中,咱們又能夠建立、啓動其餘線程。java
本質上來說,在Java中建立新線程十分簡單,只須要實例化一個Thread
實例便可:segmentfault
Thread t = new Thread();
複製代碼
可是當咱們調用該實例的start()
方法來啓動線程時,該線程其實什麼事情也沒幹就結束了,緣由是Thread
類中覆寫Runnable
接口的run()
方法的方法體以下:多線程
@Override
public void run() {
if (target != null) {
target.run();
}
}
複製代碼
這裏的target
字段是Runnable
接口的一個實例,而當Thread
構造器沒傳入任何參數時,target
爲null,線程天然也就不會執行任何操做。ide
在Java中,要建立能執行指定代碼的新線程,有如下幾種方法:學習
Thread
類派生一個自定義類,而後覆寫run()
方法。Thread
實例時,傳入一個Runnadble
接口的實例,一樣要實現接口定義的run()
抽象方法。call()
方法,幷包裝成FutureTask
類對象,再做爲參數傳入Thread
的構造器。注意:網站
run()
方法來建立新線程,而run()
方法並沒有返回值,因此這兩種方法也沒法獲取返回值。Thread
類,覆寫run()
方法public class ExecuteThread {
public static void main(String[] args) {
Thread t = new MyThread();
t.start(); // 啓動新線程
}
}
// 繼承自Thread的自定義類
class MyThread extends Thread {
@Override
public void run() {
System.out.println("start new thread!");
}
}
複製代碼
若是該類型的線程只須要使用一次,也能夠用匿名內部類的方式讓代碼更加簡單:編碼
public class ExecuteThread {
public static void main(String[] args) {
Thread t = new Thread() {
// 內部匿名類對run()方法的覆寫
@Override
public void run() {
System.out.println("start new thread!");
}
};
t.start(); // 啓動新線程
}
}
複製代碼
Runnadble
接口,實現run()
抽象方法public class ExecuteThread {
public static void main(String[] args) {
Thread t = new Thread(new MyRunnable());
t.start(); // 啓動新線程
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("start new thread!");
}
}
複製代碼
或者用Java8引入的Lambda語法進一步簡寫爲:spa
public class ExecuteThread {
public static void main(String[] args) {
Thread t = new Thread(() -> {
System.out.println("start new thread!");
});
t.start(); // 啓動新線程
}
}
複製代碼
Runnadble
接口,因此能夠繼承其餘的類,避免了單繼承的侷限性。Runnadble
接口實例,能夠被包裝成多個線程對象),實現解耦操做,代碼和線程獨立。call()
方法,幷包裝成FutureTask
對象傳入Thread
構造器public class ExecuteThread {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<String> callableInstance = new MyCallable<>("return value");
// 使用FutureTask類包裝Callable接口的實例,該對象封裝了Callable接口實現實例的call()方法的返回值。
FutureTask<String> task = new FutureTask<>(callableInstance);
Thread t = new Thread(task);
t.start(); // 啓動新線程
// 調用FutureTask實例的get()方法獲取新線程執行結束返回值。
System.out.println(task.get());
}
}
class MyCallable<V> implements Callable<V> {
private V toReturn;
public MyCallable (V val) {
toReturn = val;
}
@Override
public V call() throws Exception{
System.out.println("start new thread!");
return toReturn;
}
}
複製代碼
Runnadble
實例),能夠獲取返回值。線程池的使用避免了由於頻繁建立、銷燬線程帶來的大量系統開銷,實現了資源的複用。具體的使用方法看這篇筆記:Java多線程學習筆記——如何使用線程池。線程