Java並發編程--Fork/Join架構使用__演算法

來源:互聯網
上載者:User

      上篇部落格我們介紹了通過CyclicBarrier使線程同步,但是上述方法存在一個問題,那就是如果一個大任務跑了2個線程去完成,如果線程2耗時比線程1多2倍,線程1完成後必須等待線程2完成,等待的過程線程1沒法複用。現在我們準備解決這個問題,我們希望線程1完成自己的任務後能去協助線程2完成一部分任務。Java7引如了Fork/Join架構可以很好的解決這個問題。

         Fork/Join是一個用於並存執行任務的架構,是一個把大任務分割成若干個小任務,最後匯總每個小任務結果後得到大任務結果的架構。fork是分叉,join是結合。下面看張圖來清晰的認識一下:

 

    其實Fork/Join本質上是分治演算法的一種實現。下面我們來看怎麼具體使用:

    ForkJoinTask:我們要使用Fork/Join架構,必須首先建立一個Fork/Join任務。它提供在任務中執行fork()和join()操作的機制,通常情況下我們不需要直接繼承ForkJoinTask類,而只需要繼承它的子類,Fork/Join架構提供了以下兩個子類:

        RecursiveAction:用於沒有返回結果的任務。

        RecursiveTask :用於有返回結果的任務。

 

    ForkJoinPool:ForkJoinTask需要通過ForkJoinPool來執行,任務分割出的子任務會添加到當前背景工作執行緒所維護的雙端隊列中,進入隊列的頭部。當一個背景工作執行緒的隊列裡暫時沒有任務時,它會隨機從其他背景工作執行緒的隊列的尾部擷取一個任務。

 

下面,我們同樣實現考試系統抽題的例子。 GetQuestionsTask.java

public class GetQuestionsTask extends RecursiveTask<List> {//參數mapprivate Map map;//參數list==只放題型private List questionTypeList;public GetQuestionsTask(List questionTypeList,Map map) {this.questionTypeList = questionTypeList;this.map=map;}@Overrideprotected List compute() {System.out.println(questionTypeList.size());List list = new ArrayList();if (questionTypeList.size() < 2) {// 抽題list = getQuestions(questionTypeList,map);} else {int size = questionTypeList.size();int mid = size / 2;GetQuestionsTask task1 = new GetQuestionsTask(questionTypeList.subList(0, mid),map);GetQuestionsTask task2 = new GetQuestionsTask(questionTypeList.subList(mid, size),map);invokeAll(task1, task2);try {list = groupResults(task1.get(), task2.get());} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}return list;}//合并抽題結果private List groupResults(List list1, List list2) {System.out.println(Thread.currentThread().getName()+"開始合并結果......");// 合并返回結果List list = new ArrayList();list.addAll(list1);list.addAll(list2);System.out.println(Thread.currentThread().getName()+"合并結果結束......");return list;}// 抽題private List getQuestions(List questTypeList,Map map) {List list = new ArrayList();for(int i=0;i<questTypeList.size();i++){System.out.println(Thread.currentThread().getName()+"開始抽題......"+questionTypeList.get(i).toString());//假資料,向list中放試題list.add("0");list.add("1");list.add("2");list.add("3");list.add("4");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"抽題結束..."+questionTypeList.get(i).toString());}return list;}}


 

用戶端:

 

//該池的線程數量不會超過0*7fff個(32767)//池中維護著ForkJoinWorkerThread對象數組,數組大小由parallelism屬性決定,parallelism預設為處理器個數ForkJoinPool pool = new ForkJoinPool();GetQuestionsTask task = new GetQuestionsTask(questionTypeList, map);pool.execute(task);// 試題列表=task.get()try {List finalList = task.get();System.out.println("最終結果個數:" + finalList.size());} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}

總結:

        Fork/Join實現了“工作竊取演算法”,當一個背景工作執行緒的隊列裡暫時沒有任務時,它會隨機從其他背景工作執行緒的隊列的尾部擷取一個任務。當然,fork/join架構的使用有一定的約束條件:

1.除了fork()  和  join()方法外,線程不得使用其他的同步工具。線程最好也不要sleep()

2.線程不得進行I/O操作

3.線程不得拋出checked exception。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.