標籤:
在Java中,“線程”指java.lang.Thread類的一個執行個體以及線程的執行,主要使用的線程池是ThreadPoolExecutor以及ScheduledThreadPoolExecutor,要使用固定線程上限的線程池。
用synchronized 修飾靜態方法時,表示任何兩個不同線程的調用互斥;修飾成員函數時,表示同一對象的多線程方法調用互斥;當然了,synchronized 後的參數可以是任意對象。Synchronized保證了synchronized塊中變數的可見度,而volatile保證了所修飾變數的可見度。ReentrantLock是java.util.concurrent.locks中的一個類,與synchronized用法類似,但需要顯示的解鎖,它提供了ReentrantReadWriteLock,主要用於讀多寫少且讀不需要互斥的情境。
Java.util.concurrent.atomic包中以Atomic開頭的類提供了一些相關的原子操作,效能提升的原因是內部通過JNI的方式使用了硬體支援的CAS指令。
Object對象上的三個必備方法:wait、notify、notifyall。Nofity喚醒一個等待線程,notifyall會喚醒所有的等待線程。Wait的使用一般嵌在一個迴圈中,判斷相關的資料狀態是否達到預期,如果沒有則繼續等待,主要是為了防止虛假喚醒。
Java.util.concurrent 中CountDownLatch提供的機制是當多個線程都到達了預期狀態或者完成預期工作時觸發事件,其他線程可以等待這個事件來觸發自己後續的工作。CyclicBarrier可以協同多個線程,讓多個線程在mybarrier.wait()前等待,直到所有線程都到達了這個屏障時,再一起執行後面的動作。
CountDownLatch 與CyclicBarrier都有用於線程協調的,主要差別有:CountDownLatch在多個線程都執行了latch.countDown後才觸發事件,喚醒wait在latch上的線程,而執行countDown的線程在執行完countDown後會繼續自己線程的工作;CyclicBarrier是個柵欄,用於同步所有調用wait方法的線程,並且等所有線程都到了wait的方法時,這些線程才一起返回繼續各自的工作。另外,CountDownLatch不能迴圈使用,而CyclicBarrier可以迴圈使用。
Semaphore用於管理訊號量,訊號量物件建構時傳入訊號個數就是控制並發的數量。執行前通過acquire擷取訊號,執行後通過release歸還,如果沒有可用的訊號,aquire調用就會阻塞。與控制線程數來控制並發數相比,semaphore控制並發數的控制粒度更細。
Exchanger用於在兩個線程之間進行資料交換。線程會阻塞在Exchanger的exchange方法,直到另外一個線程也到了同一個Exchanger的exchange方法時,二者進行交換,然後兩個線程會繼續執行自身相關的代碼。
非同步呼叫的實現方式常用的有:future 和回呼函數。調用的方法會返回一個future對象,然後接著進行自己的處理,後面通過future.get()來擷取真正的傳回值。 FutureTask是future的一個具體實作類別。ThreadPoolExecutor的submit方法返回的就是一個FutureTask的具體實現。FutureTask協助實現了具體的任務執行以及與future介面中的get等方法的關聯。FutureTask協助ThreadPoolExecutor實現了對加入線程池任務的future支援,也使我們能夠實現支援future的任務調度。
加鎖互斥能夠方便地實現安全執行緒,但代價是降低了效能,而並發容器不僅追求安全執行緒,而且考慮並發,提升容器在並發環境下的效能。比較有代表性的是以CopyOnWrite和Concurrent開頭的幾個容器。
Java 中的線程管理概念梳理