宏任务和微任务执行顺序_确保任务的执行顺序
宏任務和微任務執行順序
有時有必要對線程池中的任務施加一定的順序。 JavaSpecialists通訊的第206期提出了一種這樣的情況:我們使用NIO從多個連接中讀取數據。 我們需要確保來自給定連接的事件按順序執行,但是不同連接之間的事件可以自由混合。
我想提出一個類似但略有不同的情況:我們有N個客戶。 我們希望按照給定客戶端的提交順序執行事件,但是來自不同客戶端的事件可以自由混合。 另外,有時還會有涉及多個客戶端的“匯總”任務。 此類任務應阻止所有相關客戶端的任務(但不能阻止更多!)。 讓我們看一下情況圖:
如您所見,客戶端A和客戶端B的任務被并行地愉快地處理,直到出現“匯總”任務。 到那時,不再可以處理類型A或B的任務,但是可以執行無關的任務C(前提是有足夠的線程)。 我的存儲庫中提供了這種執行程序的框架。 核心是以下界面:
public interface OrderedTask extends Runnable {boolean isCompatible(OrderedTask that); }使用此接口, A.isCompatible(B) && B.isComaptible(A)確定兩個任務是否可以并行運行(如果A.isCompatible(B) && B.isComaptible(A)則A和B可以并行運行)。 這些方法應以快速,非鎖定和時不變的方式實現。
該線程池背后的算法如下:
- 如果要添加的任務與任何現有任務不沖突,請將其添加到元素最少的線程中。
- 如果它與來自一個線程的元素沖突,則將其安排在該線程上執行(并隱式地在沖突元素之后執行,以確保提交順序得以保持)
- 如果它與多個線程沖突,則在第一個線程上等待任務的第一個線程以外的所有任務上添加任務(下面用紅色顯示),然后在該任務上執行原始任務。
有關實現的更多信息:
- 該代碼僅是概念驗證,還需要更多代碼才能使其具有生產質量(它需要代碼來執行任務中的異常處理,正確關閉等)。
- 為了獲得最佳性能,它使用可用的無鎖*結構:每個工作線程都有一個關聯的ConcurrentLinkedQueue。 為了達到睡眠直到工作可用的語義,使用了額外的信號量**
- 為了能夠將新的OrderedTask與當前執行的OrderedTask進行比較,請保留其引用的副本。 每當新元素入隊時,此副本列表就會更新(這可能會導致內存泄漏,并且如果任務不頻繁,則應研究足夠的替代方法,例如為弱引用提供額外的計時器)
- 與JavaSpecialists時事通訊中的解決方案相比,這更類似于固定線程池執行器,而時事通訊中的解決方案類似于緩存的線程池執行器。
- 如果(a)任務(大多數)短且(大多數)統一,并且(b)提交新任務的線程很少(一個或兩個),因為多個提交是互斥的(但提交和執行不是' t)
- 如果在提交“匯總”之后(并且可以執行之前)立即提交相同類型的任務,則不必要地將它們強制在一個線程上。 如果這成為問題,我們可以在匯總任務完成后添加代碼重新排列任務。
玩轉源代碼吧! (也許有一天我會花時間去除所有粗糙的邊緣)。
*有點用詞不當,因為仍然有鎖,僅在較低級別(CPU而不是OS)級別上使用,但這是公認的術語
** –基準測試表明這是性能最高的解決方案。 這是從ThreadPoolExecutor的實現中得到啟發的。
參考:在Java Advent Calendar博客上, 確保 JCG合作伙伴 Attila-Mihaly Balazs 執行任務的順序 。
翻譯自: https://www.javacodegeeks.com/2012/12/ensuring-the-order-of-execution-for-tasks.html
宏任務和微任務執行順序
總結
以上是生活随笔為你收集整理的宏任务和微任务执行顺序_确保任务的执行顺序的全部內容,希望文章能夠幫你解決所遇到的問題。