並發工具
阿新 • • 發佈:2018-01-13
main ger pic test ++ pan fin pro 青年
Fork/Join框架
在JDK7後提供一套並行任務的框架,它可以把發大任務拆分成很多的小任務,匯總每個小任務的結果得到大任務的結果。
工作竊取算法
工作竊取(work-stealing)算法是指某個線程從其他隊列裏竊取任務。
那麽,為什麽需要使用竊取算法呢?假如我們需要做一個比較大的任務,可以把這個任務分割為若幹互不依賴的子任務,為了減少線程間的競爭,把這些子任務粉筆放到不同的隊列裏,並為每個隊列創建一個單獨的線程來執行隊列裏的任務,線程和隊列一一對應。
比如A線程負責處理A隊列裏的任務,但是有的線程會先把自己隊列裏的任務幹完,而其他線程對應的隊列裏還有任務等待處理。幹完活的線程與其等著,不如去幫其他線程幹活,於是它就去其他線程的隊列裏竊取一個任務來執行。而在這時它們會訪問同一個隊列,所以為了減少竊取任務線程的和竊取任務線程之間的競爭,通常會使用雙端隊列,被竊取任務線程永遠從雙端隊列的頭部拿任務執行,而竊取任務的線程永遠從雙端隊列的尾部拿任務執行。
由兩個類完成工作:
ForkJoinTask:我們要使用ForkJoin框架,必須首先創建一個ForkJoin任務。它提供在任務中執行fork()和join()操作的機制。通常情況下,我們不需要直接繼承ForkJoin類,只需要繼承它的子類,Fork/Join框架提供了以下兩個子類。
- RecursiveAction:用於沒有返回結果的任務
- RecursiveTask:用於有返回結果的任務
ForkJoinPool:ForkJoinTask需要通過ForkJoinPool來執行。
Fork/Join有同步和異步兩種方式。
舉個例子:
青年高智商訓練班開始招生了,此時來了5萬名小夥伴參與報名篩選,但只有年齡在18~30歲之間,並且智商超過145的人才能通過。為了提高效率,每位老師最多測試不超過100名參與者,最終將通過人數進行統計。
// 參與者 public class Young { private Integer age; private String name; private Integer iq; public Young(Integer age, String name, Integer iq) { this.age = age; this.name = name; this.iq = iq; } public Integer getAge() { return age; } publicvoid setAge(Integer age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getIq() { return iq; } public void setIq(Integer iq) { this.iq = iq; } }
// 篩選接口 public interface Pick<T> { boolean pick(T person); }
// 考題 public class Exam implements Pick<Young> { @Override public boolean pick(Young person) { if (30 > person.getAge() && 18 < person.getAge() && 145 < person.getIq()) { return true; } return false; } }
// 監考老師 public class Teacher extends RecursiveTask<Integer> { private final Integer THRESHOLD = 100; private List<Young> youngs; private Integer fromIdx; private Integer toIdx; private Pick pick; private Integer count = 0; public Teacher(List<Young> youngs, Integer fromIdx, Integer toIdx, Pick pick) { this.youngs = youngs; this.fromIdx = fromIdx; this.toIdx = toIdx; this.pick = pick; } @Override protected Integer compute() { if (this.toIdx - this.fromIdx < this.THRESHOLD) { for (int i = this.fromIdx; i < this.toIdx; i ++) { if (this.pick.pick(this.youngs.get(i))) { this.count ++; } } return this.count; } else { Integer mid = (this.toIdx - this.fromIdx) / 2; Teacher teacher1 = new Teacher(this.youngs, this.fromIdx, this.fromIdx + mid, this.pick); Teacher teacher2 = new Teacher(this.youngs, this.fromIdx + mid, this.toIdx, this.pick); this.invokeAll(teacher1, teacher2); return teacher1.join() + teacher2.join(); } } }
public class Test { private static Integer COUNT = 50000; // 所有參與者 public static List<Young> makeData() { List<Young> list = new LinkedList<>(); Random rand = new Random(); Exam exam = new Exam(); Young young; int cnt = 0; for (int i = 1; i <= COUNT; i ++) { young = new Young(rand.nextInt(50), "參與者" + i, rand.nextInt(100) + 100); list.add(young); if (exam.pick(young)) { cnt ++; } } System.out.println("共有" + cnt + "參與者符合條件"); return list; } public static void main(String[] args) { ForkJoinPool pool = new ForkJoinPool(); Teacher teacher = new Teacher(makeData(), 0, COUNT - 1, new Exam()); pool.invoke(teacher); System.out.println("Fork/Join計算結果:" + teacher.join()); } }
輸出:
共有6037參與者符合條件 Fork/Join計算結果:6037
可以看出兩次結果是一致的。
並發工具