摘要:對象改變條件對象當前線程要等待線程終止之后才能從返回。如果線程在上的操作中被中斷,通道會被關閉,線程的中斷狀態會被設置,并得到一個。清除線程的中斷狀態。非公平性鎖雖然可能造成饑餓,但極少的線程切換,保證其更大的吞吐量。
聲明:Java并發的內容是自己閱讀《Java并發編程實戰》和《Java并發編程的藝術》整理來的。
個人網站
圖文并茂請戳
思維導圖下載請戳
目錄
(1)基礎概念
(2)線程
(3)鎖
(4)同步器
(5)并發容器和框架
(6)Java并發工具類
(7)原子操作類
(8)Executor框架(執行機制)
(9)其他
(一).基礎概念
1.可見性和原子性
可見性:一個線程修改了共享變量的值,另一個線程可以讀到這個修改的值。
原子性:不可被中斷的一個或一系列操作。
如何保障原子性:
使用總線鎖保證原子性。
使用緩存鎖保證原子性。
2.原子操作的三種實現:
(1).CAS(Compare And Swap 比較與交換)
需要輸入兩個數值(一個舊值和一個新值),在操作期間先比較舊值有沒有發生變化,如果沒有發生變化,才交換成新值,如果發生了變化就不交換。
存在的三大問題:
ABA問題:如果一個值原來是A,變成了B,又變成了A,那么使用CAS進行檢查時會發現它的值沒有發生變化,但是實際是發生了變化。解決方案:1.使用版本號,在變量前面追加版本號,每次變量更新都把版本號加1。JDK提供的類:AtomicStampedReference。
循環時間長開銷大。
只能保證一個共享變量的原子操作。
解決方案:JDK提供AtomicReference類來保證引用對象之間的原子性,可以把多個變量放在一個對象里進行CAS操作。
(2).鎖
(3).JDK并發包的支持
如:AtomicBoolean(用原子方式更新的boolean值),
AtomicInteger(用原子方式更新的int值),
AutomicLong(用原子方式更新的long值)。
3.同步原語
(1).volatile
特點:
可見性:對一個volatile變量的讀,總是能看到任意線程對這個volatile變量最后的寫入。
原子性:對任意單個volatile變量的讀/寫具有原子性。
從內存語義角度:volatile的寫-讀與鎖的釋放-獲取有相同的內存效果。
為了實現volatile的內存語義,編譯期在生成字節碼時,會在指令序列中插入內存屏障來禁止特定類型的處理器重排序。
從編譯器重排序規則和處理器內存屏障插入策略來看,只要volatile變量與普通變量之間的重排序可能會破壞volatile的內存語義,這種重排序就會被編譯器重排序規則和處理器內存屏障插入策略禁止。
實現原理:
將當前處理器緩存行的數據回寫到系統內存。
寫回內存的操作會使其他CPU里緩存該內存地址的數據無效。
(2).synchronized
不同情況鎖住的對象:
對于普通同步方法,鎖是當前實例對象。
對于靜態同步方法,鎖是當前類的Class對象。
對于同步方法塊,鎖是Synchronized括號里配置的對象。
(3)final
public class FinalExample { int i; //普通變量 final int j; //final變量 static FinalExample obj; public FinalExample() { //構造函數 i = 1; //寫普通域 j = 2; //寫final域 } public static void writer() { obj = new FinalExample(); } public static void reader() { FinalExample object = obj; //讀對象引用 int a = object.i; //讀普通域 int n = object.j; //讀final域 } }
寫final域的重排序規則:JMM禁止將final域的寫重排序到構造函數之外。
讀final域的重排序規則:在一個線程中,初次讀對象引用與初次讀該對象包含的final域,JMM禁止處理器重排序這兩個操作。
4.Java內存模型(JMM)
5.重排序
重排序的3種類型:
編譯器優化的重排序。
指令級并行的重排序。
內存系統的重排序。
編譯器和處理器在重排序時,會遵守數據依賴性,編譯器和處理器不會改變存在數據依賴關系的兩個操作的執行順序。
6.順序一致性
順序一致性內存模型兩大特征:
一個線程中的所有操作必須按照程序的順序來執行。
(不管程序是否同步)所有線程都只能看到一個單一的操作執行順序。在順序一致性內存模型中,每個操作都必須原子執行且立刻對所有線程可見。
7.happens-before與as-if-serial
JMM對happens-before的設計原則:只要不改變程序的執行結果(指的是單線程程序和正確同步的多線程程序),編譯器和處理器怎么優化都行。
happens-before關系的定義:
(1)如果一個操作happens-before另一個操作,那么第一個操作的執行結果將對第二個操作可見,而且第一個操作的執行順序排在第二個操作之前。
(2)兩個操作之間存在happens-before關系,并不意味著Java平臺的具體實現必須要按照happens-before關系指定的順序來執行。如果重排序之后的執行結果,與按happens-before關系來執行的結果一致,那么JMM允許這種重排序。
as-if-serial:不管怎么重排序(編譯器和處理器為了提高并行度),(單線程)程序的執行結果不能被改變。
區別:as-if-serial語義保障單線程內程序的執行結果不被改變,happens-before關系保證正確同步的多線程程序的執行結果不被改變。
8.雙重檢查鎖定與延遲初始化
使用雙重檢查鎖延遲初始化
public class DoubleCheckedLocking { private static DoubleCheckedLocking instance; public static DoubleCheckedLocking getInstance() { if(null == instance) { synchronized(DoubleCheckedLocking.class) { if(null == instance) { instance = new DoubleCheckedLocking(); } } } return instance; } }
線程A-A1:分配對象的內存空間。
線程A-A2:設置instance指向內存空間。
線程B-B1:判斷instance是否為空。
線程B-B2:由于instance不為null,線程B將訪問instance引用的對象。
線程A-A3:初始化對象
線程A-A4:訪問instance引用的對象。
存在的問題:
A2和A3重排序,線程B訪問到一個還沒初始化的對象。
解決方案:
將instance變量聲明為volatile型的。通過禁止重排序來保證線程安全的延遲初始化。
通過不允許其他線程”看到“這個重排序實現線程安全的延遲初始化。
public class InstanceFactory { private static class InstanceHolder { public static InstanceFactory instance = new InstanceFactory(); } public static InstanceFactory getInstance() { return InstanceHolder.instance; } }
9.生產者-消費者模式
(二).線程
1.什么是線程?
現代操作系統在運行一個程序時,會為其創建一個進程。現代操作系統調度的最小單元是線程,也叫輕量級進程。在一個進程里可以創建多個線程,這些線程都擁有各自的計數器,堆棧和局部變量等屬性。
2.創建線程的三種方式
(1).Thread
@Test public void testThread() { Thread thread = new Thread("myThread"); thread.start(); }
(2).Runnable
@Test public void testRunnable() { Thread thread = new Thread(new Runnable() { @Override public void run() { System.out.println("myThread"); } }); thread.start(); }
(3).Callable
@Test public void testFutureTask() throws InterruptedException, ExecutionException { ExecutorService executorService = Executors.newFixedThreadPool(2); Futurefuture = executorService.submit(new Callable () { @Override public String call() throws Exception { return "Hello,World!!!"; } }); String result = future.get(); System.out.println(result); executorService.shutdown(); }
3.Daemon線程
Daemon線程是一種支持型線程,因為它主要被用作程序中后臺調度以及支持性工作。
當一個Java虛擬機中不存在非Daemon線程的時候,Java虛擬機將會退出。
可以通過調用Thread,setDaemon(true)將線程設置為Daemon線程。
4.等待/通知機制
等待/通知機制,是指一個線程A調用了對象O的wait()方法進入等待狀態,而另一個線程B調用了對象O的notify()或者notifyAll()方法,線程A收到通知后從對象O的wait()方法返回,進而執行后續操作。
等待方遵循如下規則:
獲取對象的鎖
如果條件不滿足,那么調用對象的wait()方法,被通知后仍要檢查條件。
條件滿足則執行對應的邏輯。
while(條件不滿足){ 對象.wait(); } //處理對應的邏輯
通知方遵循如下規則:
獲得對象的鎖。
改變條件
通知所有等待在對象上的線程。
synchronized(對象){ //改變條件 對象.notifyAll(); }
5.Thread.join()
當前線程A要等待thread線程終止之后才能從thread.join()返回。
6.ThreadLocal
ThreadLocal,即線程變量,是一個以ThreadLocal對象為鍵,任意對象為值的存儲結構。這個結構被附帶在線程上,也就是說一個線程可以根據一個ThreadLocal對象查詢到綁定到這個線程上的一個值。
7.線程的終止、中斷
(1).Thread.interrupt:中斷線程
除非線程正在進行中斷它自身,否則都會接受這個方法的中斷。會調用Thread.checkAccess(),可能會拋出SecurityException。
如果線程調用了Object.wait(),Thread.sleep(),Thread.join()處于阻塞狀態,那它的堵塞狀態會被清除,并得到一個InterruptedException。
如果線程在InterruptibleChannel上的I/O操作中被中斷,通道會被關閉,線程的中斷狀態會被設置,并得到一個ClosedByInterruptedException。
(2).Thread.interrupted:測試當前線程是否被中斷。
清除線程的中斷狀態。如果連續調用兩次這個方法,第二次調用會返回false(除非當前線程再次被中斷,在第一次調用清除它的中斷狀態之后,并且在第二次調用檢查它之前)。
(3).Thread.isInterrupted:測試某個線程是否被中斷
中斷狀態是否被重置取決于傳入的值。
(三).鎖
鎖是Java并發編程中最重要的同步機制。鎖除了讓臨界區互斥執行外,還可以讓釋放鎖的線程向獲取同一個鎖的線程發送消息。
1.鎖的內存語義:
利用volatile變量的寫-讀所具有的內存語義。
利用CAS所附帶的volatile讀和volatile寫的內存語義。
2.重入鎖
(1).什么是重入鎖?
支持重進入的鎖,表示鎖能夠支持一個線程對資源的重復加鎖。重入鎖支持獲取鎖時的公平性和非公平性選擇。
(2).解決兩個問題:
線程再次獲取鎖:鎖需要去識別獲取鎖的線程是否為當前占據鎖的線程,如果是,則再次獲取鎖。
鎖的最終釋放:鎖的最終釋放要求鎖對于鎖獲取進行計數自增,計數表示當前鎖被重復獲取的次數,而鎖被釋放時,計數自減,當計數等于0時表示鎖已經釋放。
3.排他鎖:ReentrantLock
(1)公平鎖:
公平鎖釋放時,最后要寫一個volatile變量state。
公平鎖獲取時,首先會去讀volatile變量。
(2)非公平鎖:
非公平鎖釋放時,最后要寫一個volatile變量state。
非公平鎖獲取時,首先會用CAS(CompareAndSet)更新volation變量,這個操作同時具有volatile寫和volatile讀的內存語義。
(3)公平鎖與非公平鎖的區別
公平性與否是針對獲取鎖而言的。
公平鎖:如果一個鎖是公平的,那么獲取鎖的順序就應該符合請求的絕對時間順序,也就是FIFO。
非公平鎖:剛釋放鎖的線程再次獲取同步狀態的幾率會非常大,使得其他線程只能在同步隊列中等待。
公平性鎖保證了鎖的獲取按照FIFO原則,而代價是進行大量的線程切換。非公平性鎖雖然可能造成”饑餓“,但極少的線程切換,保證其更大的吞吐量。
4.Lock
(1)讀寫鎖:ReentrantReadWriteLock
讀寫鎖在同一時刻可以允許多個讀線程訪問,但是在寫線程訪問時,所有的讀線程和其他寫線程均被堵塞。
讀寫鎖的實現分析:
讀寫狀態的設計:同步狀態表示鎖被一個線程重復獲取的次數,而讀寫鎖的自定義同步需要在同步狀態(一個整型變量)上維護多個讀線程和一個寫線程的狀態,使得該狀態的設計成為讀寫鎖實現的關鍵。
寫鎖的獲取與釋放:寫鎖是一個支持重進入的排它鎖。如果當前線程已經獲取了寫鎖,則增加寫狀態。如果當前線程在獲取寫鎖時,讀鎖已經被獲取(讀狀態不為0)或者該線程不是已經獲取寫鎖的線程,則當前線程進入等待狀態。
讀鎖的獲取與釋放:如果當前線程已經獲取了讀鎖,就增加讀狀態。如果當前線程在獲取讀鎖時,寫鎖已被其他線程獲取,則進入等待狀態。
鎖降級:鎖降級指的是寫鎖降級為讀鎖。指把持住(當前擁有的)寫鎖,再獲取到讀鎖,隨后釋放(先前擁有的)讀鎖的過程。
鎖的四種狀態:無鎖,偏向鎖,輕量級鎖,重量級鎖
5.LockSupport工具
當需要阻塞或喚醒一個線程的時候,都會使用LockSupport工具類來完成相應的工作。
6.Condition接口
Condition接口提供了類似Object的監視器方法(包括wait(),wait(long timeout),notify(),以及notifyAll()方法),與Lock配合可以實現等待/通知模式。
Condition的實現:等待隊列,等待和通知。
等待隊列:等待隊列是一個FIFO隊列,在隊列中的每一個節點都包含了一個線程引用,該線程是在Condition對象上等待的線程,如果一個線程調用了Condition.await()方法,那么該線程會釋放鎖,構造成節點加入等待隊列并進入等待狀態。
等待:調用Condition的await()方法(或者以await開頭的方法),會使當前線程進入等待隊列并釋放鎖,同時線程狀態變為等待狀態。當從await()方法返回時,當前線程一定獲取了Condition相關的鎖。
通知:調用Condition的signal()方法,將會喚醒在等待隊列中等待時間最長的節點(首節點),在喚醒節點之前,會將節點移步到同步隊列。
7.避免活躍性危險
(1).死鎖
哲學家用餐問題:每個線程都擁有別的線程需要的資源,同時又等待別人擁有的資源,在獲得別的資源之前不會釋放自己手上的資源。
數據庫事務死鎖:數據庫如果發生死鎖,會選擇一個事務釋放資源。
鎖順序死鎖:線程A,B都需要鎖1,2。線程A先獲得鎖1 ,再請求鎖2 ,線程B先獲得鎖2,再請求鎖1 。
8.死鎖的避免與診斷
(1).內置鎖:只要沒有獲得鎖,就會一直等待下去。
(2).定時鎖:使用Lock類的定時tyLock功能。可以指定一個超時時限,在等待超過該時間后會返回失敗信息。
(3).線程轉儲
避免死鎖的四種方式:
避免一個線程同時獲得多個鎖。
避免一個線程在鎖內同時占用多個資源,盡量保證每個鎖只獲得一個資源。
使用定時鎖。
對于數據庫鎖,加鎖和解鎖必須在一個數據庫連接里,否則會出現解鎖失敗的情況。
9.饑餓,糟糕的響應性,活鎖
饑餓:線程由于無法訪問它需要的資源而不能繼續執行,引發饑餓最常見的資源是CPU時鐘周期。
活鎖通常發送在處理事務消息的應用程序中,如果不能成功地處理事務消息,那么消息機制將回滾整個事務,將這個事務放在等待隊列的開頭。
當多個相互協作的線程都對彼此響應從而修改各自的狀態,并使得任何一個線程都無法繼續執行時,就發生了活鎖。
在并發應用中,通過等待隨機長度的時間和回退可以有效地避免活鎖的發生。
(四).同步器
(1).實現
同步隊列:同步器依賴內部的同步隊列(一個FIFO雙向隊列)來完成同步狀態的管理,當前線程獲得同步狀態失敗時,同步器會將當前線程以及等待狀態等信息構造成為一個節點并將其加入同步隊列,同時會阻塞當前線程,當同步狀態釋放時,會把首節點中的線程喚醒,使其再次嘗試獲取同步狀態。
獨占式同步狀態獲取與釋放:在獲取同步狀態時,同步器維護一個隊列,獲取狀態失敗的線程會被加入隊列中并在隊列中進行自旋,移除隊列的原因時自旋獲取了同步狀態且前驅節點時頭節點。在釋放同步狀態時,同步器調用tryRelease(int arg)方法釋放同步狀態,然后喚醒頭節點的后繼結點。
共享式同步狀態獲取與釋放:共享式獲取與獨占式獲取最主要的區別在于同一時刻能否有多個線程同時獲取同步狀態。
獨占式超時獲取同步狀態:在指定的時間段內獲取同步狀態,如果獲取到同步狀態返回true,否則,返回false。
(2).AbstractQueuedSynchronized
用來構建鎖或者其他同步組件的基礎框架,使用了一個int成員變量表示同步狀態,通過內置的FIFO隊列來完成資源獲取線程的排隊工作。
提供了三個對同步狀態進行修改的方法:
getState():獲取當前同步狀態。
setState(int new3State):設置當前同步狀態。
compareAndSetState(int export,int update):使用CAS設置當前狀態,該方法能夠保證狀態設置的原子性。
(五).并發容器和框架
(1).ConcurrentHashMap
與HashMap,HashTable對比:
HashMap是線程不安全,且可能導致程序死循環。
HashTable效率低下。
ConcurrentHashMap的鎖分段技術可有效提升訪問效率。首先將數據分成一段一段的存儲,然后給每一段數據配一把鎖,當一個線程占用鎖訪問其中一個段的數據的時候,其他段的數據也能被其他線程訪問。
ConCurrentHashMap的結構:ConCurrentHashMap是由Segment數組結構和HashEntry數組結構組成。
(2).ConcurrentLinkedQueue
ConcurrentLinkedQueue由head節點和tail節點組成,每個節點(Node)由節點元素(item)和指向下一個節點(next)的引用組成,從而組成一張鏈表結構的隊列。
(3).阻塞隊列
插入:當隊列滿時,隊列會堵塞插入元素的線程,直到隊列不滿。
移除:當隊列為空,獲取元素的線程會等待線程為非空。
實現原理:
使用通知模式實現。當生產者往滿的隊列里添加元素時會堵塞生產者,當消費者消費了一個隊列中的元素后,會通知生產者當前隊列可用。
1.ArrayBlockingQueue
數組實現的有界阻塞隊列,按照先進先出的原則對元素進行排序。
2.LinkedBlockingQueue
繼承了AbstractQueue類,實現了BlockingQueue接口。
采用先進先出的排列方式,頭結點是入隊時間最長的元素,尾結點是入隊時間最短的元素。新結點添加到隊尾,從隊頭彈出結點。
鏈表隊列的特點是:跟基于數組的隊列相比有更大的吞吐量,但在大多并發應用中性能會比較差。
LinkedBlockingQueue可以在創建的時候傳遞一個容量參數,限制隊列的長度,不設定的情況下,默認是Integer.MAX_VALUE。在沒有超過隊列邊界的情況下,每次添加會自動創建鏈表結點。
3.PriorityBlockingQueue
是一個支持優先級的無界阻塞隊列。默認情況下時自然順序升序排序。
4.SychronousQueue
SynchronousQueue是一個不存儲元素的堵塞隊列,每一個put操作必須等待一個take操作,否則不能繼續添加元素。
5.DelayQueue
延遲隊列:無界隊列,只有延遲過期的任務才能加入隊列。隊列的隊首元素是在過去延遲過期最長的元素。如果沒有延遲到期,隊列中就沒有元素,調用poll方法會返回null。當調用元素的getDelay(TimeUnit.NANOSECONDS)方法返回等于或小于0的值時,出現到期。
DelayQueue的應用場景:a.緩存系統:把需要緩存的元素加入DelayQueue中,讓一個線程循環測試是否能從DelayQueue中獲取元素,能表示緩存到期。b.定時任務調度。
Timer和DelayQueue的區別?Timer只能處理單個后臺線程,而DelayQueue可以處理多個。
6 . LinkedTransferQueue
LinkedTransferQueue是一個由鏈表結構組成的無界阻塞TransferQueue隊列。
7 . LinkedBlockingDeque
一個由鏈表結構組成的雙向阻塞隊列,可以運用在“工作竊取”模式中。
(4).Fork/Join框架
用于并行執行任務,把一個大任務分割成小任務,再把每個小任務的結果匯總成大任務結果。Fork是把一個大任務切分成若干子任務并行執行,Join是合并這些子任務的執行結果。
(5).工作竊取算法
指某個線程從其他隊列里竊取任務來執行。為了減少竊取任務線程和別竊取任務線程之間的競爭,使用雙端隊列,被竊取任務線程從雙端隊列的頭部拿任務執行,竊取任務線程從雙端隊列的尾部拿任務執行。
工作竊取算法的優點:充分利用線程進行并行計算,減少線程間的競爭。
工作竊取算法的缺點:在某些情況下還是存在競爭,比如雙端隊列里只有一個任務時,并且該算法會消耗更多的系統資源,比如創建多個線程和多個雙端隊列。
(六).Java并發工具類
1.CyclicBarrier
一組線程在到達一個屏障(同步點)前被堵塞,直到最后一個線程到達屏障時,屏障才會放行,這組線程才能繼續執行。
應用場景:可以用于多線程計算數據,最后合并計算結果。
CyclicBarrier與CountDownLatch的區別:CountDownLatch的計數器只能使用一次,而CyclicBarrier的計數器可以使用reset()方法重置。CountDownLatch的計數是減法,CyclicBarrier的計數是加法。
2.Semaphore
用來控制同時訪問特定資源的線程數量,通過協調各個線程,以保證合理的使用公共資源。
應用場景:可以用于流量控制,特別是公共資源有限的應用場景,比如數據庫連接。
3.CountDownLatch
允許一個或多個線程等待其他線程完成操作。
4.Exchanger
Exchanger是一個用于線程間協作的工具類。Exchanger用于進行線程間的數據交換。它提供一個同步點,在這個同步點,兩個線程可以交換彼此的數據。這兩個線程通過exchange方法交換數據,如果第一個線程先執行exchange()方法,會一直等待第二個線程也執行exchange()方法,當兩個線程都到達同步點時,這兩個線程就可以交換數據,將本線程生產出來的數據傳遞給對方。
應用場景:用于遺傳算法。
(七).原子操作類
1.原子更新基本類型類
AtomicBoolean
AtomicInteger
AtomicLong
2.原子更新數組
AtomicIntegerArray
AtomicLongArray
AtomicReferenceArray
3.原子更新引用類型
AtomicReference
AtomicReferenceFieldUpdater 原子更新引用類型里的字段
AtomicMarkableReference 原子更新帶有標記位的引用類型。
4.原子更新字段類
AtomicIntegerFieldUpdater 原子更新整型的字段的更新器
AtomicLongFieldUpdater 原子更新長整型字段的更新器
AtomicStampedReference 原子更新帶有版本號的引用類型。該類將整數值與引用關聯起來,可用于原子的更新數據和數據的版本號,可以解決使用CAS進行原子更新時可能出現的ABA問題。
(八).Executor框架(執行機制)
從JDK5開始,把工作單元和執行機制分離開來,工作單元包括Runnable和Callable,而執行機制由Executor框架提供。
1.異步計算的結果:FutureTask和Future
2.任務執行
(1).Executor(核心接口)
Executor的生命周期:創建,提交,開始,完成
(2).ExecutorService接口(繼承自Executor)
ExecutorService的生命周期:運行,關閉,已終止
ExecutorService.shutDown和ExecutorService.shutDownNow的區別
調用的方法 | 作用 |
---|---|
shutDown | 不再允許新的任務添加到等待隊列,正在執行的任務和在等待隊列中的任務會執行完畢再關閉。 |
shurDownNow | 立刻關閉。需要知道正在執行但是還沒執行完畢的任務。 |
ExecutorService.submit()和ExecutorService.execute()的區別:接口ExecutorService的execute()方法是繼承自Executor。
調用的方法 | 作用 |
---|---|
execute | 用于提交不需要返回值的任務,所以無法判斷任務是否被線程池執行成功。 |
submit | 用于提交需要返回值的任務。線程池會返回一個Future類型的對象,通過這個Future對象可以判斷任務是否執行成功,并且通過Future的get()方法來獲取返回值,get()方法會阻塞線程直到任務完成。 |
ExecutorService的創建:
調用 | 分類 | 使用 |
---|---|---|
Executors.newSingleThreadExecutor() | ThreadPoolExecutor | 應用場景:適用于需要保證順序地執行各個任務;并且在任意時間點,不會有多個線程活動的應用場景。 |
Exectors.newFiexedThreadPool() | ThreadPoolExecutor | 1.創建一個線程池,具有固定線程數,運行在共享的無界隊列中。2.在大多數時候,線程會主動執行任務,當所有的線程都在執行任務時,有新的任務加入進來,就會進入等待隊列(可以有源源不斷的任務加入進來,因為是無界隊列),當有空閑的線程,等待隊列中的任務就會被執行。3.如果有線程在執行過程中因為執行失敗要關閉,新創建的線程會替失敗的線程執行接下來的任務。4.如果想要關閉這個線程池,可以調用ExecutorService的shutDown方法。應用場景:適用于為了滿足資源管理的需求,而需要限制當前線程數量的應用場景,它適用于負載比較重的服務器。 |
Executors.newCachedThreadPool() | ThreadPoolExecutor | 應用場景:適用于執行很多短期異步任務的小程序,或者是負載較輕的服務器。 |
Executors.newScheduledThreadPool() | ScheduledThreadPoolExecutor | 應用場景:適用于需要多個后臺線程執行周期任務,同時為了滿足管理的需求而需要限制后臺線程的數量的應用場景。 |
Executors.newSingleThreadScheduledExecutor() | ScheduledThreadPoolExecutor | 應用場景:需要單個后臺線程執行周期任務,同時需要保證順序地執行各個任務。 |
3.任務:Runnable接口和Callable接口
(九).其他
1.jstack
打開cmd,輸入:
jps 查看pid(進程號)
jstack pid
2.資源限制:指在進行并發編程時,程序的執行速度受到計算機硬件資源或軟件資源的限制。
3.上下文切換
減少上下文切換的方法:
無鎖并發編程
CAS算法
使用最少線程
使用協程
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/69538.html
摘要:方法由兩個參數,表示期望的值,表示要給設置的新值。操作包含三個操作數內存位置預期原值和新值。如果處的值尚未同時更改,則操作成功。中就使用了這樣的操作。上面操作還有一點是將事務范圍縮小了,也提升了系統并發處理的性能。 這是java高并發系列第21篇文章。 本文主要內容 從網站計數器實現中一步步引出CAS操作 介紹java中的CAS及CAS可能存在的問題 悲觀鎖和樂觀鎖的一些介紹及數據庫...
摘要:筆記來源并發編程與高并發解決方案并發基礎綜述多級緩存緩存一致性亂序執行優化內存模型規定抽象結構同步八種操作及規則并發的優勢與風險并發與高并發基本概念基本概念并發同時擁有兩個或者多個線程,如果程序在單核處理器上運行,多個線程將交替地換入或者換 筆記來源:【IMOOC】Java并發編程與高并發解決方案 并發基礎 綜述: CPU多級緩存:緩存一致性、亂序執行優化 Java內存模型:JM...
高級并發對象 到目前為止,本課程重點關注從一開始就是Java平臺一部分的低級別API,這些API適用于非常基礎的任務,但更高級的任務需要更高級別的構建塊,對于充分利用當今多處理器和多核系統的大規模并發應用程序尤其如此。 在本節中,我們將介紹Java平臺5.0版中引入的一些高級并發功能,大多數這些功能都在新的java.util.concurrent包中實現,Java集合框架中還有新的并發數據結構。 ...
摘要:相比與其他操作系統包括其他類系統有很多的優點,其中有一項就是,其上下文切換和模式切換的時間消耗非常少。因為多線程競爭鎖時會引起上下文切換。減少線程的使用。很多編程語言中都有協程。所以如何避免死鎖的產生,在我們使用并發編程時至關重要。 系列文章傳送門: Java多線程學習(一)Java多線程入門 Java多線程學習(二)synchronized關鍵字(1) java多線程學習(二)syn...
摘要:在中一般來說通過來創建所需要的線程池,如高并發原理初探后端掘金閱前熱身為了更加形象的說明同步異步阻塞非阻塞,我們以小明去買奶茶為例。 AbstractQueuedSynchronizer 超詳細原理解析 - 后端 - 掘金今天我們來研究學習一下AbstractQueuedSynchronizer類的相關原理,java.util.concurrent包中很多類都依賴于這個類所提供的隊列式...
摘要:在中一般來說通過來創建所需要的線程池,如高并發原理初探后端掘金閱前熱身為了更加形象的說明同步異步阻塞非阻塞,我們以小明去買奶茶為例。 AbstractQueuedSynchronizer 超詳細原理解析 - 后端 - 掘金今天我們來研究學習一下AbstractQueuedSynchronizer類的相關原理,java.util.concurrent包中很多類都依賴于這個類所提供的隊列式...
閱讀 3460·2019-08-30 13:15
閱讀 1400·2019-08-29 18:34
閱讀 822·2019-08-29 15:18
閱讀 3480·2019-08-29 11:21
閱讀 3246·2019-08-29 10:55
閱讀 3688·2019-08-26 10:36
閱讀 1868·2019-08-23 18:37
閱讀 1816·2019-08-23 16:57