詳解三種java實現(xiàn)多線程的方式
java中實現(xiàn)多線程的方法有兩種:繼承Thread類和實現(xiàn)runnable接口。
1.繼承Thread類,重寫父類run()方法
public class thread1 extends Thread {
public void run() {
for (int i = 0; i < 10000; i++) {
System.out.println("我是線程"+this.getId());
}
}
public static void main(String[] args) {
thread1 th1 = new thread1();
thread1 th2 = new thread1();
th1.run();
th2.run();
}
}
run()方法只是普通的方法,是順序執(zhí)行的,即th1.run()執(zhí)行完成后才執(zhí)行th2.run(),這樣寫只用一個主線程。多線程就失去了意義,所以應該用start()方法來啟動線程,start()方法會自動調(diào)用run()方法。上述代碼改為:
public class thread1 extends Thread {
public void run() {
for (int i = 0; i < 10000; i++) {
System.out.println("我是線程"+this.getId());
}
}
public static void main(String[] args) {
thread1 th1 = new thread1();
thread1 th2 = new thread1();
th1.start();
th2.start();
}
}
通過start()方法啟動一個新的線程。這樣不管th1.start()調(diào)用的run()方法是否執(zhí)行完,都繼續(xù)執(zhí)行th2.start()如果下面有別的代碼也同樣不需要等待th2.start()執(zhí)行完成,而繼續(xù)執(zhí)行。(輸出的線程id是無規(guī)則交替輸出的)
2.實現(xiàn)runnable接口
public class thread2 implements Runnable {
public String ThreadName;
public thread2(String tName){
ThreadName = tName;
}
public void run() {
for (int i = 0; i < 10000; i++) {
System.out.println(ThreadName);
}
}
public static void main(String[] args) {
thread2 th1 = new thread2("線程A");
thread2 th2 = new thread2("線程B");
th1.run();
th2.run();
}
}
和Thread的run方法一樣Runnable的run只是普通方法,在main方法中th2.run()必須等待th1.run()執(zhí)行完成后才能執(zhí)行,程序只用一個線程。要多線程的目的,也要通過Thread的start()方法(注:runnable是沒有start方法)。上述代碼修改為:
public class thread2 implements Runnable {
public String ThreadName;
public thread2(String tName){
ThreadName = tName;
}
public void run() {
for (int i = 0; i < 10000; i++) {
System.out.println(ThreadName);
}
}
public static void main(String[] args) {
thread2 th1 = new thread2("線程A");
thread2 th2 = new thread2("Thread-B");
Thread myth1 = new Thread(th1);
Thread myth2 = new Thread(th2);
myth1.start();
myth2.start();
}
}
3.使用ExecutorService、Callable、Future實現(xiàn)有返回結果的多線程(JDK5.0以后)
可返回值的任務必須實現(xiàn)Callable接口,類似的,無返回值的任務必須Runnable接口。執(zhí)行Callable任務后,可以獲取一個Future的對象,在該對象上調(diào)用get就可以獲取到Callable任務返回的Object了,再結合線程池接口ExecutorService就可以實現(xiàn)傳說中有返回結果的多線程了。下面提供了一個完整的有返回結果的多線程測試例子,在JDK1.5下驗證過沒問題可以直接使用。代碼如下:
import java.util.concurrent.*;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
/**
* 有返回值的線程
*/
@SuppressWarnings("unchecked")
public class Test {
public static void main(String[] args) throws ExecutionException,
InterruptedException {
System.out.println("----程序開始運行----");
Date date1 = new Date();
int taskSize = 5;
// 創(chuàng)建一個線程池
ExecutorService pool = Executors.newFixedThreadPool(taskSize);
// 創(chuàng)建多個有返回值的任務
List<Future> list = new ArrayList<Future>();
for (int i = 0; i < taskSize; i++) {
Callable c = new MyCallable(i + " ");
// 執(zhí)行任務并獲取Future對象
Future f = pool.submit(c);
// System.out.println(">>>" + f.get().toString());
list.add(f);
}
// 關閉線程池
pool.shutdown();
// 獲取所有并發(fā)任務的運行結果
for (Future f : list) {
// 從Future對象上獲取任務的返回值,并輸出到控制臺
System.out.println(">>>" + f.get().toString());
}
Date date2 = new Date();
System.out.println("----程序結束運行----,程序運行時間【"
+ (date2.getTime() - date1.getTime()) + "毫秒】");
}
}
class MyCallable implements Callable<Object> {
private String taskNum;
MyCallable(String taskNum) {
this.taskNum = taskNum;
}
public Object call() throws Exception {
System.out.println(">>>" + taskNum + "任務啟動");
Date dateTmp1 = new Date();
Thread.sleep(1000);
Date dateTmp2 = new Date();
long time = dateTmp2.getTime() - dateTmp1.getTime();
System.out.println(">>>" + taskNum + "任務終止");
return taskNum + "任務返回運行結果,當前任務時間【" + time + "毫秒】";
}
}
代碼說明:
上述代碼中Executors類,提供了一系列工廠方法用于創(chuàng)先線程池,返回的線程池都實現(xiàn)了ExecutorService接口。
public static ExecutorService newFixedThreadPool(int nThreads)
創(chuàng)建固定數(shù)目線程的線程池。
public static ExecutorService newCachedThreadPool()
創(chuàng)建一個可緩存的線程池,調(diào)用execute 將重用以前構造的線程(如果線程可用)。如果現(xiàn)有線程沒有可用的,則創(chuàng)建一個新線程并添加到池中。終止并從緩存中移除那些已有 60 秒鐘未被使用的線程。
public static ExecutorService newSingleThreadExecutor()
創(chuàng)建一個單線程化的Executor。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
創(chuàng)建一個支持定時及周期性的任務執(zhí)行的線程池,多數(shù)情況下可用來替代Timer類。
ExecutoreService提供了submit()方法,傳遞一個Callable,或Runnable,返回Future。如果Executor后臺線程池還沒有完成Callable的計算,這調(diào)用返回Future對象的get()方法,會阻塞直到計算完成。
總結:實現(xiàn)java多線程的2種方式,runable是接口,thread是類,runnable只提供一個run方法,建議使用runable實現(xiàn) java多線程,不管如何,最終都需要通過thread.start()來使線程處于可運行狀態(tài)。第三種方法是聽群里的兄弟們介紹的,所以就百度補上了。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助。
相關文章
java.net.http.HttpClient使用示例解析
這篇文章主要為大家介紹了java.net.http.HttpClient使用示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-08-08
Retrofit+RxJava實現(xiàn)帶進度條的文件下載
這篇文章主要為大家詳細介紹了Retrofit+RxJava實現(xiàn)帶進度條的文件下載,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-06-06
Spring?Boot使用Schedule實現(xiàn)定時任務的方法
這篇文章主要介紹了Spring?Boot使用Schedule實現(xiàn)定時任務,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-03-03
ajax實時監(jiān)測與springboot的實例分析
本文將介紹如何使用 AJAX 技術結合 Spring Boot 構建一個實時反饋用戶輸入的應用,我們將創(chuàng)建一個簡單的輸入框,當用戶在輸入框中鍵入文本時,應用將異步地向后端發(fā)送請求,感興趣的朋友跟隨小編一起看看吧2024-07-07
Java8新特性之類型注解_動力節(jié)點Java學院整理
這篇文章主要介紹了Java8新特性之類型注解的相關資料,需要的朋友可以參考下2017-06-06

