Java獲得多線程的返回結果方式

一:Java創建線程方式

繼承Thread類或者實現Runnable接口。
但是Runnable 的 run() 方法是不帶返回值的,那如果我們需要一個耗時任務在執行完之後給予返回值,應該怎麼做呢?

第一種方法:在 Runnable 的實現類中設置一個變量 V,在 run 方法中將其改變爲我們期待的結果,然後通過一個 getV() 方法將這個變量返回。

package com.test.thread;

import java.util.*;
import sun.swing.AccumulativeRunnable;
//獲得線程的返回結果方式一
/*
 *在runnable實現類中設置一個變量x,在run方法中將其改變爲我們期待的結果,然後通過一個getX()方法將這個變量返回 
 */
public class RunnableTest {
		public static void main(String[] args) throws Exception {
			System.out.println("使用Runnable獲取返回結果");
			List<Thread> workers = new ArrayList<>(10);
			List<RunnableAcction> tasks = new ArrayList<>(10);
			//創建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累加的結果:"+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) - 運行結束,結果爲 %d\n",Thread.currentThread().getName(),result);
			}
		     public int getResult() {//獲取線程返回結果
		            return result;
		     }
		}
}

第二種方法:使用 Callable 和 FutureTask。

使用 FutureTask 的過程如下:
(1)通過一個 Callable 任務或者一個 Runnable(一開始就指定 result)任務構造 FutureTask;
(2)將 FutureTask 交給 Thread 去運行;
(3)使用 FutureTask 的 get 方法(或者 Thread 的 join 方法)阻塞當前線程直到獲得任務的結果。

import java.util.*;
import java.util.concurrent.*;

public class CallableTest {

    public static void main(String[] args) throws Exception {
        System.out.println("使用 Callable 獲得返回結果:");
        
        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() 方法會阻塞直到獲得結果
        }
        System.out.println("累加的結果: " + 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) - 運行結束,結果爲 %d\n",
            Thread.currentThread().getName(), result);
            return result;
        }
    } 
}

二:FutureTask介紹

FutureTask可用於異步獲取執行結果或取消執行任務的場景。通過傳入Runnable或者Callable的任務給FutureTask,直接調用其run方法或者放入線程池執行,之後可以在外部通過FutureTask的get方法異步獲取執行結果。因此,**FutureTask非常適合用於耗時的計算,主線程可以在完成自己的任務後,再去獲取結果。**另外,FutureTask還可以確保即使調用了多次run方法,它都只會執行一次Runnable或者Callable任務,或者通過cancel取消FutureTask的執行等。

一個FutureTask 可以用來包裝一個 Callable 或是一個runnable對象。因爲FurtureTask實現了Runnable方法,所以一個 FutureTask可以提交(submit)給一個Excutor執行(excution)。

FutureTask執行多任務計算的使用場景:

利用FutureTask和ExecutorService,可以用多線程的方式提交計算任務,主線程繼續執行其他任務,當主線程需要子線程的計算結果時,再異步獲取子線程的執行結果。

import java.util.*;
import java.util.concurrent.*;

public class FutureTest1 {

    public static void main(String[] args) {
    
        Task task = new Task();// 新建異步任務,然後執行futureTask
        FutureTask<Integer> future = new FutureTask<Integer>(task) {
            // 異步任務執行完成,回調
            @Override
            protected void done() {
                try {
                    System.out.println("future.done():" + get());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }
        };
        // 創建線程池(使用了預定義的配置)
        ExecutorService executor = Executors.newCachedThreadPool();
        executor.execute(future);

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
        // 可以取消異步任務
        // future.cancel(true);

        try {
            // 阻塞,等待異步任務執行完畢-獲取異步任務的返回值
            System.out.println("future.get():" + future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    // 異步任務
    static class Task implements Callable<Integer> {
        // 返回異步任務的執行結果
        @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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章