您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關如何分析java并發編程的藝術和并發編程,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
通常我們在使用編發編程時,主要目的是為了程序能夠更快的處理,但是并不是說更多的線程就一定能夠讓程序變得足夠快,有時候太多的線程反而消耗了更多的資源,反而讓程序執行得更緩慢
一.CPU的上下文切換
就算是單核CPU是能夠處理多線程任務的,它只是不停的切換線程來執行,讓我們感覺是多線程執行
下圖是串行執行和并發執行的耗時對比
從圖中我們可以看到,在數量不達到千萬級的時候,串行和并行的耗時幾乎差不多,這是因為線程在創建和上下文切換時需要一定的時間開銷.
如何減少上下文的切換似乎是我們在并發編程時需要注意的一點.
無鎖編發編程,多線程并發強占鎖時,會引起頻繁的上下文切換,我們可以使用分段式的方法來處理數據,不同的線程處理不同段的數據,避免使用鎖
使用最少的線程.避免創建大量無效線程,任務量很少的情況,會讓大量線程處于等待狀態,浪費資源
二.多線程在java中的使用
volatile和synchronize
當我們使用volatile變量修飾時會引發的兩件事:
1.當前處理器的數據會回寫到系統內存
2.這個回寫內存會使處理器中的這個內存地址無效化
這兩件事說明了什么呢.在java中使用volatile可以讓多個線程共享一個變量,在多個線程獲取這個變量的時候,該線程會等待正在改變這個變量的線程釋放掉才會去讀取,這讓我們多線程在共享這個變量時,才能保持唯一性
synchronized實現同步的基礎
1.對于普通方法,鎖的是當前實例對象
2.對于靜態方法.鎖的是當前class對象
3.對于方法塊,鎖的是作用域里的所有對象
通俗一點說,一個普通方法鎖,其實是鎖的是實例對象來調用時,針對于這個實例對象來說他是同步的,如果我們有多個這個實例對象同時調用它內部同步方法時,實際上還是并發請求,對于靜態方法來說,他在java中只有一份,那么無論調用幾次他都是一個同步調用,最后的方法塊類似于我們的普通方法,不同的地方就是鎖的作用域內的所有對象都被加鎖,屬于這個線程的私有變量
三.并發編程模型的兩個關鍵問題
1.線程之間如何通信
2.線程之間如何同步
大部分時間中,我們不會關心線程之間如何通信,我們在實際編程中會遇到線程之間如何同步一個變量的問題,使用volatile來修飾一個變量是一個非常好的方法,在jdk8之后的jvm內存模型中,對象的實例是存儲于本地棧,一個變量在使用volatile后,該對象實例的引用還是在本地內存中,而該對象的的變量則被拷貝到了主內存中用于共享,不在私有,簡單來說,就是各個線程任然保留有這個變量的內存地址只是不同的內存地址被指向了主內存中的同一個變量
四.Java并發容器和框架
ConcurrentHashMap的實現原理與使用
ConcurrentHashMap是線程安全且高效的HashMap
ConcurrentHashMap的結構圖
ConcurrentHashMap是由Segment數組結構和HashEntry數組結構組成。Segment是一種可重入鎖(ReentrantLock),在ConcurrentHashMap里扮演鎖的角色;HashEntry則用于存儲鍵值對數據。一個ConcurrentHashMap里包含一個Segment數組。Segment的結構和HashMap類似,是一種數組和鏈表結構。一個Segment里包含一個HashEntry數組,每個HashEntry是一個鏈表結構的元素,每個Segment守護著一個HashEntry數組里的元素,當對HashEntry數組的數據進行修改時,必須首先獲得與它對應的Segment鎖
Java里的阻塞隊列
ArrayBlockingQueue:一個由數組結構組成的有界阻塞隊列。
LinkedBlockingQueue:一個由鏈表結構組成的有界阻塞隊列。
PriorityBlockingQueue:一個支持優先級排序的無界阻塞隊列。
DelayQueue:一個使用優先級隊列實現的無界阻塞隊列。
SynchronousQueue:一個不存儲元素的阻塞隊列。
LinkedTransferQueue:一個由鏈表結構組成的無界阻塞隊列。
LinkedBlockingDeque:一個由鏈表結構組成的雙向阻塞隊列。
五.線程池
線程池是我們使用得最多的線程框架,合理地使用它可以為我們帶來很多好處
1.降低資源消耗,避免重復創建線程
2.提高響應速度,保持一定量的等待線程,不用每次都重新創建線程
3.提高線程的管理性
這里不得不提一下阿里的java編碼規范中明確的指出了:線程池不允許使用 Executors 去創建,而是通過 ThreadPoolExecutor 的方式,這樣的處理方式讓寫的同學更加明確線程池的運行規則,規避資源耗盡的風險,
六.并發編程實踐
生產者和消費者模式
在并發編程中使用生產者和消費者模式能夠解決絕大多數并發問題。該模式通過平衡生產線程和消費線程的工作能力來提高程序整體處理數據的速度。在線程世界里,生產者就是生產數據的線程,消費者就是消費數據的線程。在多線程開發中,如果生產者處理速度很快,而消費者處理速度很慢,那么生產者就必須等待消費者處理完,才能繼續生產數據。同樣的道理,如果消費者的處理能力大于生產者,那么消費者就必須等待生產者。為了解決這種生產消費能力不均衡的問題,便有了生產者和消費者模式。
我寫了一個簡單的生產消費,但是并沒有同步鎖也沒有同享變量,于是產生了消費者為-1的情況
于是我讓這個變量在線程中共享,但是拋出了IllegalMonitorStateException異常,大致意思就是說拋出這個異常表明線程嘗試等待一個對象的監視器或者去通知其他正在等待這個對象監視器的線程時,但是沒有擁有這個監視器的所有權,這就證明了,其實對于共享變量操作時實際上只能有一個線程去操作
因為我們對鎖的操作不正確,無法釋放鎖,所以我用ReentrantLock實現了
以上就是如何分析java并發編程的藝術和并發編程,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。