最近在看線程這一塊的東西,所以之前的那篇文章就是用來記錄的,但看起來好簡單的樣子,哈哈哈!
這兩天看的是Fork/Join?分而治之的思想,Doug Lea大師的JUC還是挺強的,學并發編程應該沒有人不知道這個大佬吧!
上篇少記錄了一個東西,叫守護線程,即Thread.setDaemon(boolean on);當參數為false的時候,沒有意思,當參數為true的時候,即調用該方法的線程與當前的線程共生死,就是當前線程結束了后無論調用setDeamon(true)的線程是否結束,它都會結束;這個這么看起來雖然用處不大,但是在使用單元測試的時候,即junit測試,使用@Test進行測試線程時,當測試線程走完后,調用的線程都會結束,就是因為守護線程的存在,導致會出現這樣的現象;所以在測試線程的時候盡量不要使用junit單元測試,還是使用main方法測試比較好。
現在開始談談Fork/Join啦,分而治之,就是將一個大任務拆分到多個小任務,然后小任務同時執行,執行完后將每個小任務運算結果進行合并,這樣能夠加快程序運行的速度。像這種分而治之的思想在歸并排序算法中能體現出來。
Fork/Join的使用標準范式:
ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask task = new ForkJoinTask();
pool.invoke(task);
Result = task.join();
ForkJoinPool其實是個線程池繼承自JDK的線程池ExecutorService,說白就是多線程執行多個任務,然后將結果進行合并預算,來提升程序的運行的速度
ForkJoinTask主要有兩個常用的實現類RecursiveAction以及RecursiveTask<T>?即一個是同步帶有返回值的,后面那個異步不帶有返回值的
RecursiveTask<T>的使用示例:
class UseRecursiveTask extends RecursiveTask<T> {protected T compute(){//do something...UseRecursiveTask task1 = new UseRecursiveTask();UseRecursiveTask task2 = new UseRecursiveTask();invokeAll(task1,task2);//再次調用task1和task2的compute()方法return task1.join() + task2.join();//阻塞并等待獲取結果值}
}
//主方法
public static void main(String [] arg0){ForkJoinPool pool = new ForkJoinPool();UseRecursiveTask task = new UseRecursiveTask<T>();pool.invoke(task);T result = task.join();//開始執行,進入阻塞,等待拆分任務全部執行。//do something...
}
RecursiveAction的使用示例:
class UseRecursiveAction extends RecursiveAction {protected void compute(){//do something...UseRecursiveAction action1 = new UseRecursiveAction();UseRecursiveAction action2 = new UseRecursiveAction();List<UseRecursiveAction> list = new ArrayList<UseRecursiveAction>();list.add(action1);list.add(action2);Collection<UseRecursiveAction> collection = invokeAll(list);for(UseRecursiveAction action : collection){action.join();//異步執行}}
}
//主線程
public static void main(String [] arg0){ForkJoinPool pool = new ForkJoinPool();UseRecursiveAction action = new UseRecursiveAction();pool.execute(action);//開始異步執行//這里可執行其他業務邏輯//....action.join();//進入阻塞狀態,等待異步線程執行完畢
}
上面就是兩種示例,在Fork/Join中其實還有一種思想叫工作密取(Worker-Stealing),就是空閑的線程會從繁忙線程的任務隊列中,從任務隊列后面獲取一個任務去執行,在ForkJoinPool?中就已經實現好了。
既然談到了這個,就簡單的看了一下源代碼,在ForkJoinPool?類中有個內部類叫WorkQueue,維護了一個它的數組,用來儲存每個任務的,看了一下它的源代碼,感覺有點艱難,還是等下次變得更強的時候再研究吧!
?