excelexportentity中设置null不显示的方法_一般人不知道的线程间数据交换Exchanger
線程間的數據共享除了定義一個共享數據然后各個線程去訪問這種方式外,還可以使用Exchanger交換數據。
簡單案例
首先看看Exchanger的運用,Exchanger最簡單的測試代碼,如下圖:
對應打印的結果如下:
線程2創建對象java.lang.Object@3f6d4362
線程1創建對象java.lang.Object@c986ad7
線程2得到的類java.lang.Object@c986ad7
線程1得到的類java.lang.Object@3f6d4362
可以看出來線程2創建的對象與線程1得到的線程是同一個對象,也就是他們指向的是同一個引用。
Exchanger源碼分析
Exchanger只提供了兩個exchange方法,一個是只帶交換的數據參數,另外一個不僅有數據參數,還有時間限制,這也從側面說明exchange是一個阻塞線程的方法,并且可以指定阻塞時間,這里我們先分析下不帶時間參數的exchange方法,源碼分析主流程如下圖:
左邊是exchange方法的代碼流程圖,比較簡單可以明顯的看出來主要依靠兩個方法slotExchange與arenaExchange方法,流程主要有兩步,首先嘗試從slotExchange方法獲取值,如果獲取為null則再從arenaExchange方法獲取,當返回還是null時則拋出中斷異常,否則最終返回結果。
slotExchange源碼分析
上圖中右邊的分析圖是slotExchange方法的主要代碼圖,再分析這個方法前先說明一下Exchanger的一個內部類Node,Node有7個屬性,這里先說明三個屬性item(創建node線程要交換出去的值)、match(創建node線程要獲取的值)、parked(創建node的線程);每個線程再執行到Exchanger方法后都會創建一個Node。
理解這個基本概念后,再來快速過一下slotExchange方法流程,方法包含兩個循環,第一個循環分析如下:
首先判斷Exchanger的slot是否為null,如果不為空則嘗試修改slot值為null,如果修改成功則返回slot的item,并設置slot的match,并喚醒slot的線程,交換成功。如果設置失敗則說明有其他線程正在修改slot,即存在競爭,這是會判斷機器的CPU數,如果大于1則會初始化Exchanger的Node[] arena(這個是下個方法說明),進入下一個循環。
如果slot為null則判斷arena是否為null,如果不為null則直接返回null,表示由arenaExchange去執行。
如果都不是則嘗試當前線程的node的item設置為要交換的值,同時嘗試設置為slot,設置成功則跳出循環,失敗則進入下次循環;
第一個循環主要包含兩步,如果slot不為null則嘗試交換值,交換成功就返回,否則就嘗試設置slot的值,設置成功就跳出循環;在cpu是多個的情況下又存在競爭的情況下會再arenaExchange去處理。
這個循環如果跳出來了則說明設置slot成功,那么當前線程只需要等待node的match不為null就行,所以第二個循環的判斷條件就是node的match不為null,如果為null就掛起,當喚醒的時候再判斷,直到node的match不為null則返回match的值。
分析arenaExchange方法
在slotExchange方法中會在存在競爭修改slot并且運行程序的機器的CPU大于1時會初始化Node[] arena屬性,在第二次修改slot還存在競爭失敗時就會返回null,這個時候就到了arenaExchange方法上場了。
arenaExchange也是一個for的無限循環,每次取出當前線程的Node來獲取進行處理,這里再介紹node一個屬性index,用來標記node再arena數組的位置,處理流程的簡單分析如下:
首先根據node的index獲取j(計算方法:index<<7+ABASE(1<<7的常量),原因后面特別說明),如果不為null則嘗試修改arena的第j項為null,如果成功則返回arena[j]的node的item的值,并設置match,最后喚醒node保存的線程。
第二步如果node為null則把當前線程的node的item設置為要交換出去的值,然后嘗試修改arena[j]的值為當前線程的node,如果修改成功則循環判斷match的值,當不為null則返回值,否則判斷線程中斷等條件后則掛起線程,等喚醒再判斷。
第三步也就是node不為null,但是在第一步更新失敗后,會根據node的bound與Exchange的bound等對比,計算index的值,有時會增長有時會減少,然后進入下一個循環判斷。
總結這三步主要目的如下,首先是嘗試從arena找一個節點來交換數據,如果交換成功則喚醒對應的線程并返回交換結果,如果交換失敗則更新index,再次嘗試尋找并交換,如果在找到的arena[j]為null則嘗試新建一個node并保存進arena,掛起線程等待喚醒。
對之前的arena的j特別說明,把index擴大再作為數組的索引,原因是內存在加載數組一個元素時會把附近的也加載,而修改過后會把加載出來的設置為過期,為了避免這種浪費在數組間隔一定位置在設置值。
總結
Exchanger利用一個Node類型的屬性slot實現線程間的交換,如果slot為null則初始化一個并設置item為需要交換的值,然后掛起,當其他線程進來的時候看到slot為null則取出node的item值,然后把自己要交換的值設置進match上,然后喚醒node中線程。
利用一個屬性也夠了,但是在并發的情況下吞吐量并不高,所以又建了一個Node的數組arena,線程在arena一個個找不為null的值,嘗試修改直到修改成功,則獲取node的item,再設置match并喚醒線程。如果找到的為null則自己主動new一個node并設置item,然后掛起等待喚醒。
Java程序員日常學習筆記,如理解有誤歡迎各位交流討論!
總結
以上是生活随笔為你收集整理的excelexportentity中设置null不显示的方法_一般人不知道的线程间数据交换Exchanger的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: babel原理_带你了解 snowpac
- 下一篇: 布尔表达式的语法及语义分析程序_XSS语