淺談Java獲得多線程的返回結(jié)果方式(3種)
一:Java創(chuàng)建線程方式
繼承Thread類或者實現(xiàn)Runnable接口。
但是Runnable 的 run() 方法是不帶返回值的,那如果我們需要一個耗時任務在執(zhí)行完之后給予返回值,應該怎么做呢?
第一種方法:在 Runnable 的實現(xiàn)類中設置一個變量 V,在 run 方法中將其改變?yōu)槲覀兤诖慕Y(jié)果,然后通過一個 getV() 方法將這個變量返回。
package com.test.thread;
import java.util.*;
import sun.swing.AccumulativeRunnable;
//獲得線程的返回結(jié)果方式一
/*
*在runnable實現(xiàn)類中設置一個變量x,在run方法中將其改變?yōu)槲覀兤诖慕Y(jié)果,然后通過一個getX()方法將這個變量返回
*/
public class RunnableTest {
public static void main(String[] args) throws Exception {
System.out.println("使用Runnable獲取返回結(jié)果");
List<Thread> workers = new ArrayList<>(10);
List<RunnableAcction> tasks = new ArrayList<>(10);
//創(chuàng)建10個線程,每個線程分別負責累加1-10,11-20,.........,91-100
for(int i=0;i<10;i++) {
RunnableAcction task = new RunnableAcction(i*10+1,(i+1)*10);
Thread work = new Thread(task,"累加器線程"+i);
workers.add(work);
tasks.add(task);
work.start();
}
int total = 0;
for(int i = 0;i<workers.size();i++) {
workers.get(i).join();
total += tasks.get(i).getResult();
}
System.out.println("\n累加的結(jié)果:"+total);
}
static final class RunnableAcction implements Runnable{
private int a;
public RunnableAcction(int a, int b) {
super();
this.a = a;
this.b = b;
}
private int b;
private int result;
@Override
public void run() {
result = 0;
try {
for(int i=a;i<= b;i++) {
result += i;
Thread.sleep(100);
}
} catch (Exception e) {
// TODO: handle exception
}
System.out.printf("(%s) - 運行結(jié)束,結(jié)果為 %d\n",Thread.currentThread().getName(),result);
}
public int getResult() {//獲取線程返回結(jié)果
return result;
}
}
}
第二種方法:使用 Callable 和 FutureTask。
使用 FutureTask 的過程如下:
(1)通過一個 Callable 任務或者一個 Runnable(一開始就指定 result)任務構(gòu)造 FutureTask;
(2)將 FutureTask 交給 Thread 去運行;
(3)使用 FutureTask 的 get 方法(或者 Thread 的 join 方法)阻塞當前線程直到獲得任務的結(jié)果。
import java.util.*;
import java.util.concurrent.*;
public class CallableTest {
public static void main(String[] args) throws Exception {
System.out.println("使用 Callable 獲得返回結(jié)果:");
List<FutureTask<Integer>> futureTasks = new ArrayList<>(10);
// 新建 10 個線程,每個線程分別負責累加 1~10, 11~20, ..., 91~100
for (int i = 0; i < 10; i++) {
AccumCallable task = new AccumCallable(i * 10 + 1, (i + 1) * 10);
FutureTask<Integer> futureTask = new FutureTask<>(task);
futureTasks.add(futureTask);
Thread worker = new Thread(futureTask, "慢速累加器線程" + i);
worker.start();
}
int total = 0;
for (FutureTask<Integer> futureTask : futureTasks) {
total += futureTask.get(); // get() 方法會阻塞直到獲得結(jié)果
}
System.out.println("累加的結(jié)果: " + total);
}
static final class AccumCallable implements Callable<Integer> {
private final int begin;
private final int end;
public AccumCallable(int begin, int end) {
this.begin = begin;
this.end = end;
}
@Override
public Integer call() throws Exception {
int result = 0;
for (int i = begin; i <= end; i++) {
result += i;
Thread.sleep(100);
}
System.out.printf("(%s) - 運行結(jié)束,結(jié)果為 %d\n",
Thread.currentThread().getName(), result);
return result;
}
}
}
二:FutureTask介紹
FutureTask可用于異步獲取執(zhí)行結(jié)果或取消執(zhí)行任務的場景。通過傳入Runnable或者Callable的任務給FutureTask,直接調(diào)用其run方法或者放入線程池執(zhí)行,之后可以在外部通過FutureTask的get方法異步獲取執(zhí)行結(jié)果。因此,**FutureTask非常適合用于耗時的計算,主線程可以在完成自己的任務后,再去獲取結(jié)果。**另外,F(xiàn)utureTask還可以確保即使調(diào)用了多次run方法,它都只會執(zhí)行一次Runnable或者Callable任務,或者通過cancel取消FutureTask的執(zhí)行等。
一個FutureTask 可以用來包裝一個 Callable 或是一個runnable對象。因為FurtureTask實現(xiàn)了Runnable方法,所以一個 FutureTask可以提交(submit)給一個Excutor執(zhí)行(excution)。
FutureTask執(zhí)行多任務計算的使用場景:
利用FutureTask和ExecutorService,可以用多線程的方式提交計算任務,主線程繼續(xù)執(zhí)行其他任務,當主線程需要子線程的計算結(jié)果時,再異步獲取子線程的執(zhí)行結(jié)果。
import java.util.*;
import java.util.concurrent.*;
public class FutureTest1 {
public static void main(String[] args) {
Task task = new Task();// 新建異步任務,然后執(zhí)行futureTask
FutureTask<Integer> future = new FutureTask<Integer>(task) {
// 異步任務執(zhí)行完成,回調(diào)
@Override
protected void done() {
try {
System.out.println("future.done():" + get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
};
// 創(chuàng)建線程池(使用了預定義的配置)
ExecutorService executor = Executors.newCachedThreadPool();
executor.execute(future);
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
// 可以取消異步任務
// future.cancel(true);
try {
// 阻塞,等待異步任務執(zhí)行完畢-獲取異步任務的返回值
System.out.println("future.get():" + future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
// 異步任務
static class Task implements Callable<Integer> {
// 返回異步任務的執(zhí)行結(jié)果
@Override
public Integer call() throws Exception {
int i = 0;
for (; i < 10; i++) {
try {
System.out.println("異步任務:"+Thread.currentThread().getName() + "_" + i);
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return i;
}
}
}
參考文章:
https://blog.csdn.net/chenliguan/article/details/54345993
https://blog.csdn.net/linchunquan/article/details/22382487
https://segmentfault.com/a/1190000007767231
到此這篇關(guān)于淺談Java獲得多線程的返回結(jié)果方式的文章就介紹到這了,更多相關(guān)Java 多線程的返回結(jié)果內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺談web服務器項目中靜態(tài)請求和動態(tài)請求處理
這篇文章主要介紹了淺談web服務器項目中靜態(tài)請求和動態(tài)請求處理,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-07-07
springBoot集成redis(jedis)的實現(xiàn)示例
Redis是我們Java開發(fā)中,使用頻次非常高的一個nosql數(shù)據(jù)庫,本文主要介紹了springBoot集成redis(jedis)的實現(xiàn)示例,具有一定的參考價值,感興趣的可以了解一下2023-09-09
SSO單點登錄系統(tǒng)實現(xiàn)原理及流程圖解
這篇文章主要介紹了SSO單點登錄系統(tǒng)實現(xiàn)原理及流程圖解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-12-12
基于Java Callable接口實現(xiàn)線程代碼實例
這篇文章主要介紹了基于Java Callable接口實現(xiàn)線程代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-08-08
Windows環(huán)境IDEA下Ranger1.2.0源碼編譯詳細流程
本文給大家講解Windows環(huán)境IDEA下Ranger1.2.0源碼編譯過程,通過配置Tomcat,發(fā)布?security-admin-web項目,編譯啟動tomcat即可完成,需要的朋友參考下2021-06-06

