Java線程池

內存模型

爲了保證共享內存的正確性(可見性、有序性、原子性),內存模型定義了共享內存系統中多線程程序讀寫操做行爲的規範。經過這些規則來規範對內存的讀寫操做,從而保證指令執行的正確性。它與處理器有關、與緩存有關、與併發有關、與編譯器也有關。他解決了CPU多級緩存、處理器優化、指令重排等致使的內存訪問問題,保證了併發場景下的一致性、原子性和有序性。java

內存模型解決併發問題主要採用兩種方式:限制處理器優化使用內存屏障編程

ava程序是須要運行在Java虛擬機上面的,Java內存模型(Java Memory Model ,JMM)就是一種符合內存模型規範的,屏蔽了各類硬件和操做系統的訪問差別的,保證了Java程序在各類平臺下對內存的訪問都能保證效果一致的機制及規範。數組

Java內存模型規定了全部的變量都存儲在主內存中,每條線程還有本身的工做內存,線程的工做內存中保存了該線程中使用到的變量的主內存副本拷貝,線程對變量的全部操做都必須在工做內存中進行,而不能直接讀寫主內存。不一樣的線程之間也沒法直接訪問對方工做內存中的變量,線程間變量的傳遞均須要本身的工做內存和主存之間進行數據同步進行。緩存

而JMM就做用於工做內存和主存之間數據同步過程。他規定了如何作數據同步以及何時作數據同步。多線程

主內存主要對應於Java堆中的對象實例數據部分。工做內存則對應於虛擬機棧中的部分區域。併發

JMM是一種規範,目的是解決因爲多線程經過共享內存進行通訊時,存在的本地內存數據不一致、編譯器會對代碼指令重排序、處理器會對代碼亂序執行等帶來的問題。目的是保證併發編程場景中的原子性、可見性和有序性。性能

在開發多線程的代碼的時候,咱們能夠直接使用synchronized等關鍵字來控制併發,歷來就不須要關心底層的編譯器優化、緩存一致性等問題。因此,Java內存模型,除了定義了一套規範,還提供了一系列原語,封裝了底層實現後,供開發者直接使用。優化

 

原子性

在Java中,爲了保證原子性,提供了兩個高級的字節碼指令monitorentermonitorexit。在synchronized的實現原理文章中,介紹過,這兩個字節碼,在Java中對應的關鍵字就是synchronizedatom

所以,在Java中可使用synchronized來保證方法和代碼塊內的操做是原子性的。spa

可見性

Java內存模型是經過在變量修改後將新值同步回主內存,在變量讀取前從主內存刷新變量值的這種依賴主內存做爲傳遞媒介的方式來實現的。

Java中的volatile關鍵字提供了一個功能,那就是被其修飾的變量在被修改後能夠當即同步到主內存,被其修飾的變量在每次使用以前都從主內存刷新。所以,可使用volatile來保證多線程操做時變量的可見性。

除了volatile,Java中的synchronizedfinal兩個關鍵字也能夠實現可見性,只不過實現方式不一樣。

有序性

在Java中,可使用synchronizedvolatile來保證多線程之間操做的有序性。實現方式有所區別:

volatile關鍵字會禁止指令重排。synchronized關鍵字保證同一時刻只容許一條線程操做。

好了,這裏簡單的介紹完了Java併發編程中解決原子性、可見性以及有序性可使用的關鍵字。讀者可能發現了,好像synchronized關鍵字是萬能的,他能夠同時知足以上三種特性,這其實也是不少人濫用synchronized的緣由。

可是synchronized是比較影響性能的,雖然編譯器提供了不少鎖優化技術,可是也不建議過分使用。

synchronized 關鍵字和 volatile 關鍵字的區別
synchronized關鍵字和volatile關鍵字比較
volatile關鍵字是線程同步的輕量級實現,因此volatile性能確定比synchronized關鍵字要好。可是volatile關
鍵字只能用於變量而synchronized關鍵字能夠修飾方法以及代碼塊。synchronized關鍵字在JavaSE1.6以後進
行了主要包括爲了減小得到鎖和釋放鎖帶來的性能消耗而引入的偏向鎖和輕量級鎖以及其它各類優化以後執行
效率有了顯著提高,實際開發中使用 synchronized 關鍵字的場景仍是更多一些。
多線程訪問volatile關鍵字不會發生阻塞,而synchronized關鍵字可能會發生阻塞
volatile關鍵字能保證數據的可見性,但不能保證數據的原子性。synchronized關鍵字二者都能保證。
volatile關鍵字主要用於解決變量在多個線程之間的可見性,而 synchronized關鍵字解決的是多個線程之間訪
問資源的同步性。 

線程池

線程池提供了一種限制和管理資源(包括執行一個任務)。 每一個線程池還維護一些基本統計信息,例如已完成任務
的數量。

使用線程池的好處:
下降資源消耗。 經過重複利用已建立的線程下降線程建立和銷燬形成的消耗。
提升響應速度。 當任務到達時,任務能夠不須要的等到線程建立就能當即執行。
提升線程的可管理性。 線程是稀缺資源,若是無限制的建立,不只會消耗系統資源,還會下降系統的穩定性,
使用線程池能夠進行統一的分配,調優和監控。

實現Runnable接口和Callable接口的區別
若是想讓線程池執行任務的話須要實現的Runnable接口或Callable接口。 Runnable接口或Callable接口實現類均可
以被ThreadPoolExecutor或ScheduledThreadPoolExecutor執行。二者的區別在於 Runnable 接口不會返回結果但
是 Callable 接口能夠返回結果。

執行execute()方法和submit()方法的區別是什麼呢?
1) execute() 方法用於提交不須要返回值的任務,因此沒法判斷任務是否被線程池執行成功與否;
2)submit()方法用於提交須要返回值的任務。線程池會返回一個future類型的對象,經過這個future對象能夠判斷
任務是否執行成功,而且能夠經過future的get()方法來獲取返回值,get()方法會阻塞當前線程直到任務完成,而使用
get(long timeout,TimeUnit unit) 方法則會阻塞當前線程一段時間後當即返回,這時候有可能任務沒有執行
完。

Atomic 原子類

Atomic 是指一個操做是不可中斷的。即便是在多個線程一塊兒執行的時候,一個操做一旦開始,就不
會被其餘線程干擾。

併發包 java.util.concurrent 的原子類都存放在java.util.concurrent.atomic 下

JUC 包中的原子類是哪4類?基本類型使用原子的方式更新基本類型AtomicInteger:整形原子類AtomicLong:長整型原子類AtomicBoolean :布爾型原子類數組類型使用原子的方式更新數組裏的某個元素AtomicIntegerArray:整形數組原子類AtomicLongArray:長整形數組原子類AtomicReferenceArray :引用類型數組原子類引用類型AtomicReference:引用類型原子類AtomicStampedRerence:原子更新引用類型裏的字段原子類AtomicMarkableReference :原子更新帶有標記位的引用類型對象的屬性修改類型AtomicIntegerFieldUpdater:原子更新整形字段的更新器AtomicLongFieldUpdater:原子更新長整形字段的更新器AtomicStampedReference :原子更新帶有版本號的引用類型。該類將整數值與引用關聯起來,可用於解決原子的更新數據和數據的版本號,能夠解決使用 CAS 進行原子更新時可能出現的 ABA 問題。

相關文章
相關標籤/搜索