如何提升Java並行程序性能

在Java程序中,多線程幾乎已經無處不在。與單線程相比,多線程程序的設計和實現略微困難,但經過多線程,咱們卻能夠得到多核CPU帶來的性能飛躍,從這個角度說,多線程是一種值得嘗試的技術。那麼如何寫出高效的多線程程序呢?緩存

  • 有關多線程的誤區:線程越多,性能越好網絡

很多初學者可能認爲,線程數量越多,那麼性能應該越好。由於程序給咱們的直觀感覺老是這樣。一個兩個線程可能跑的很難,線程一多可能就快了。但事實並不是如此。由於一個物理CPU一次只能執行一個線程,多個線程則意味着必須進行線程的上下文切換,而這個代價是很高的。所以,線程數量必須適量,最好的狀況應該是N個CPU使用N個線程,而且讓每一個CPU的佔有率都達到100%,這種狀況下,系統的吞吐量才發揮到極致。但現實中,不太可能讓單線程獨佔CPU達到100%,一個廣泛的願意是由於IO操做,不管是磁盤IO仍是網絡IO都是很慢的。線程在執行中會等待,所以效率就下來了。這也就是爲何在一個物理核上執行多個線程會感受效率高了,對於程序調度來講,一個線程等待時,也正是其它線程執行的大好機會,所以,CPU資源獲得了充分的利用。多線程

  • 儘量不要掛起線程併發

多線程程序免不了要同步,最直接的方法就是使用鎖。每次只容許一個線程進入臨界區,讓其它相關線程等待。等待有2種,一種是直接使用操做系統指令掛起線程,另一種是自旋等待。在操做系統直接掛起,是一種簡單粗暴的實現,性能較差,不太適用於高併發的場景,由於隨之而來的問題就是大量的線程上下文切換。若是能夠,嘗試一下進行有限的自旋等待,等待不成功再去掛起線程也不遲。這樣頗有可能能夠避免一些無謂的開銷。JDK中ConcurrentHashMap的實現裏就有一些自旋等待的實現。此外Java虛擬機層面,對synchronized關鍵字也有自旋等待的優化。高併發

  • 善用「無鎖」性能

阻塞線程會帶來性能開銷,所以,一種提供性能的方案就是使用無鎖的CAS操做。JDK中的原子類,如AtomicInteger正是使用了這種方案。在高併發環境中,衝突較多的狀況下,它們的性能遠遠好於傳統的鎖操做(《實戰Java高併發程序設計》 P158)。優化

  • 處理好「僞共享」問題操作系統

你們知道,CPU有一個高速緩存Cache。在Cache中,讀寫數據的最小單位是緩存行,若是2個變量存在一個緩存行中,那麼在多線程訪問中,可能會相互影響彼此的性能。所以將變量存放於獨立的緩存行中,也有助於變量在多線程訪問是的性能提高(《實戰Java高併發程序設計》 P200),大量的高併發庫都會採用這種技術。線程

相關文章
相關標籤/搜索