併發調試及jdk8的併發新支持

併發的調試較單線程調試更復雜,且併發的問題不一定能復現,

1、介紹eclipse的條件斷點

在加斷點的地方,右鍵選擇條件斷點:

設置進入斷點的條件:

 

 

案例:ArrayList(線程不安全)併發添加元素的越界的調試分析:

設置條件斷點:

線程1越界後,拋出異常,終止運行,線程0繼續運行:

2、使用jstack -l pid:分析線程鎖情況

 如,可以看到java的死鎖的情況。死鎖介紹

3、java8對併發的新支持

1、LongAdder

先說下AtomicLong。在32位操作系統中,64位的long 和 double 變量由於會被JVM當作兩個分離的32位來進行操作,所以不具有原子性。而使用AtomicLong能讓long的操作保持原子型。實現方式是內部有個volatile  value 變量,當多線程併發自增,自減時,均通過自旋的cas 指令從機器指令級別操作保證併發的原子性。AtomicLong中有個內部變量value保存着實際的long值,所有的操作都是針對該變量進行。也就是說,高併發環境下,value變量其實是一個熱點,也就是N個線程競爭一個熱點。

LongAdder的基本思路就是分散熱點,將value值分散到一個數組中,不同線程會命中到數組的不同槽中,各個線程只對自己槽中的那個值進行CAS操作,這樣熱點就被分散了,衝突的概率就小很多。如果要獲取真正的long值,只要將各個槽中的變量值累加返回。有點像鎖優化中減小鎖的粒度,空間換時間,如jdk7中的ConcurrentHashMap中的“分段鎖”類似思想。

LongAdder來說,內部有一個base變量,一個Cell[]數組。
base變量:非競態條件下,直接累加到該變量上,和AtomicLong類似,
Cell[]數組:競態條件下,累加個各個線程自己的槽Cell[i]中值;             即:value=base+∑i=0nCell[i]

可以參考:https://segmentfault.com/a/1190000015865714

2、CompletableFuture

 先說下Future和Callable實現了用於阻塞式獲取結果,Future.get()介紹是等到有結果返回,是阻塞的。

方法:String java.util.concurrent.Future.get() throws InterruptedException, ExecutionException

註釋:Waits if necessary for the computation to complete, and then retrieves its result.

CompletableFuture是當任務完成後得到通知,自動調用一些回調方法,執行其他的操作,避免了任務的阻塞,是Future的增強。使用介紹可以參考:https://www.jianshu.com/p/6bac52527ca4

3、StampedLock

ReentrantReadWriteLock使得多個讀線程同時持有讀鎖(只要寫鎖未被佔用),而寫鎖是獨佔的。

但是,在讀線程非常多,寫線程很少的情況下,很容易產生“飢餓”問題,

StampedLock是讀寫鎖的改進,讀不阻塞寫,Optimistic reading(樂觀讀模式)是一種優化的讀模式。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章