JAVA並發總結-基礎篇

來源:互聯網
上載者:User

標籤:並發   java   安全執行緒   多線程   


多線程 1. java中有幾種方法可以實現一個線程?
繼承Thread類,實現Runnable介面建立一個線程的唯一方法是執行個體化java.lang.Thread類(或其子類),並調用其start()方法
2. 如何停止一個正在啟動並執行線程?
調用ThreadInstanceA.inerrupt()方法,這樣當A線程在Thread的sleep,join方法,或者Object的wait方法的時候會直接拋出InerruptedException,捕捉後便可退出。
public void shutdown() {stop = true;this.interrupt();try {this.join();}catch(InterruptedException ie) {}}
停止一個線程的最佳方法是讓它執行完畢,沒有辦法立即停止一個線程,但你可以控制何時或什麼條件下讓他執行完畢通過條件變數控制線程的執行,線程內部檢查變數狀態,外部改變變數值可控制停止執行。為保證線程間的即時通訊,需要使用volatile關鍵字或鎖,確保讀線程與寫線程間變數狀態一致。下面給一個模板:
public class BestPractice extends Thread {private volatile boolean finished = false; // ① volatile條件變數public void stopMe() {finished = true; // ② 發出停止訊號}@Overridepublic void run() {while (!finished) { // ③ 檢測條件變數// do dirty work // ④業務代碼}}}
當④處的代碼阻塞於wait()或sleep()時,線程不能立刻檢測到條件變數。因此②處的代碼最好向上邊一樣同時調用interrupt()方法。從源碼上看Join內部也是調用wait,那麼他是如何做到“線上程B中調用了線程A的Join()方法,直到線程A執行完畢後,才會繼續執行線程B“的呢?wait()會釋放對象上的鎖的,並且等待獲得鎖的線程和調用wait的線程有一個本質差別,一旦一個線程調用wait方法,他就進入了等待集合中,當鎖可獲得時,線程不能立即解除阻塞。他維持阻塞狀態一直到另一個線程調用同一個鎖上的notifyAll/notify方法為止;在B中調用A.wait,這時a作為提供監視器的對象(鎖的提供者),B為真正阻塞的線程(鎖的使用者),所以線程B會一直停在執行a.join這一句代碼的位置上,又因為沒有其他的線程會調用a.notify結束阻塞,所以會一直等到a線程執行完畢,當一個線程結束時,他會立即釋放所有他鎖住對象上的鎖,於是B線程從a.join下一行繼續執行。若想打破這種機制,可以調用a.interrupt(),這時,線程b可以不必受剛才的約束
3. notify()和notifyAll()有什麼區別?
X.notify()方法會喚醒在X對象上wait的其他線程中的一個(只能喚醒等待中的線程中的一個,具體喚醒哪一個線程,由JVM決定);X.notify()方法會喚醒所有 在X對象上wait的線程,但是由於要繼續執行wait後面的代碼,必須在sychronized塊中獲得相應X對象的鎖,所以一旦一個線程獲得鎖後,其他的線程就會等待其他線程釋放鎖並自己獲得鎖後才能繼續執行。notify容易導致死結,當僅剩一個線程處於活動狀態並且也要轉入wait的時候,如果調用notify喚醒其他阻塞的線程,因為只會喚醒一個線程,如果喚醒後的線程發現還是不滿足條件,繼續調用wait,有可能所有線程都阻塞了,造成死結。
4. sleep()和 wait()有什麼區別?
sleep不會讓出鎖,wait會讓出鎖。
5. 什麼是Daemon線程?它有什麼意義?
使用者線程:就是我們平時建立的普通線程.守護線程:主要是用來服務使用者線程. 定期檢查系統的狀態等。當線程只剩下守護線程的時候,JVM就會退出.但是如果還有其他的任意一個使用者線程還在,JVM就不會退出.
6. java如何?多線程之間的通訊和協作?
所謂的線程通訊,指的是通過發送訊號喚醒另一個線程,一般用在存線上程互斥的情況下。使用上可以選用Object.wait,Object.notify/notifyall,配合sychronized關鍵字。也可以選用concurrent包中提供的,Lock(ReetrantLock),Condition(Lock.newCondition()),在Lock.lock獲得鎖後通過Condition.await(),Condition.signal/signalAll實現線程間的協作
7. 什麼是可重新進入鎖(ReentrantLock)?
concurrent包中提供的替代Object中的監視器的一個顯示的鎖對象。繼承子Lock介面,用來保護從lock()方法,到unlock()的臨界地區內的代碼。配合條件對象(Condition)使用。condition通過獲得reentrantlock得到對臨界代碼的訪問權。
8. 當一個線程進入某個對象的一個synchronized的執行個體方法後,其它線程是否可進入此對象的其它方法?
一個對象的synchronize執行個體方法,就相當於在一個普通的實力方法中sychronized(this),會佔有當前對象的鎖,此時其他線程不可以訪問這個對象另外的synchronize執行個體方法,但是可以訪問其他非同步方法。
9. synchronized和java.util.concurrent.locks.Lock的異同?
基本作用相同,都是為瞭解決線程間互斥的問題。隱式的鎖和條件(synchronized,wait,notify)方式,雖然寫起代碼來比較簡潔,但他也存在一些缺點:-你不能中斷一個正在試圖獲得鎖的線程。-試圖獲得鎖時不能設定逾時-每個鎖只有一個條件,有時顯得不夠用(比如讀寫鎖問題)顯示的鎖和條件(ReetrantLock,Condition)解決了上面隱式鎖的幾個問題:-lock方法不能被中斷,所以提供了trylock方法進行鎖測試和逾時- 通過調用帶逾時的tryLock方法,如果線上程等待擷取一個鎖時被中斷,將拋出一個InterruptException異常,以此打破死結。- 也可以調用lockInterruptibly方法,相當於一個逾時設為無限的trylock方法。- await方法也提供逾時設定讀寫鎖問題:在讀多寫少的情況下保證資料的ACID的同時提高系統的處理能力,只有“讀-讀”可以不加鎖。“讀-寫”,“寫-讀”,“寫-寫”還是需要加鎖。concurrent包中提供ReentrantReadWriteLock類,協助建立讀鎖和寫鎖。readLock()得到一個可被多個讀操作共用的讀鎖,但他會排斥所有的寫操作。writeLock()得到一個寫鎖,他會排斥其他所有的讀操作和寫操作。另外顯示鎖還提供了公平等特性。
10. 樂觀鎖和悲觀鎖的理解及如何?,有哪些實現方式?
悲觀鎖認為每次拿資料的時候資料都有可能被其他人修改,所以每次拿資料都需要加鎖,這樣別的人想拿資料就會被block,直到自己釋放鎖。實現可以利用前面介紹的Object.wait/notify配合synchronized,或者concurrent包提供的Lock.lock配合Condition.await/signal。樂觀鎖認為拿資料的時候不會被人修改,所以在拿去資料的時候不加鎖,只是在回寫資料的時候確認一下這期間是否有人更新這個資料,可以使用版本號碼等機制。適合讀多寫少的場合,可以提高程式的輸送量。如果寫比較多就容易發生資料不一致導致retry,反而效率低。實現方式可以用CAS(check-and-set)方式,或者使用volitate變數。
Java demoAtomicInteger atom = new AtomicInteger(1);boolean r = atom.compareAndSet(1, 2);
並發架構 11. SynchronizedMap和ConcurrentHashMap有什麼區別?
SynchronizedMap時HashMap的加鎖版本,效率不高,而且Map介面本身提供keySet,values,entrySet,這些迭代器提供的是視圖而不是副本,所以當一個線程正在迭代Map中的元素時,另一個線程可能正在修改其中的元素。此時,在迭代元素時就可能會拋出 ConcurrentModificationException異常。ConcurrentHashMap實現ConcurrentMap介面,ConcurrentHashMap採用分段加鎖的設計,不同的線程不會造成阻塞。只有在size等操作時才需要鎖住整個表,大大提高了效率。
12. CopyOnWriteArrayList可以用於什麼應用情境?
適合於讀很多寫很少的情境,比如一些人員資訊,參數配置等會經常被讀到,但是很少修改的情況。
安全執行緒 13. 什麼叫安全執行緒?servlet是安全執行緒嗎?
引用概念:如果你的代碼所在的進程中有多個線程在同時運行,而這些線程可能會同時運行這段代碼。如果每次運行結果和單線程啟動並執行結果是一樣的,而且其他的變數的值也和預期的是一樣的,就是安全執行緒的。我理解的是安全執行緒問題都是由全域變數及靜態變數引起的,是要麼多線程不對同一資料的訪問,要麼採用機制確保對同一資料訪問的安全性進行保障(比如對資料的操作是原子操作,鎖機制,包括悲觀鎖和樂觀鎖)。servlet是多線程的,同時一個servlet實作類別只會有一個執行個體對象,也就是它是Singleton的,所以多個線程是可能會訪問同一個servlet執行個體對象的,但是這並不能說明servlet就是線程不安全的,servlet是否安全執行緒是由它的實現來決定的,如果它內部的屬性或方法會被多個線程改變,它就是線程不安全的,反之,就是安全執行緒的。
14. 同步有幾種實現方法?
加鎖,join,阻塞隊列
15. volatile有什麼用?能否用一句話說明下volatile的應用情境?
Java語言規範第三版中對volatile的定義如下: java程式設計語言允許線程訪問共用變數,為了確保共用變數能被準確和一致的更新,線程應該確保通過獨佔鎖定單獨獲得這個變數。Java語言提供了volatile,在某些情況下比鎖更加方便。如果一個欄位被聲明成volatile,java線程記憶體模型確保所有線程看到這個變數的值是一致的。volatile關鍵字對一個執行個體的域的同步訪問提供了一個免鎖(lock-free)機制。如果把域聲明為volatile,那麼編譯器和虛擬機器就知道該域可能會被另一個線程並發更新。對象內需要同步的域值少,使用鎖顯得浪費和繁瑣情境,這時使用volatile。一些並發容器(ConcurrentHashMap,etc)的實現內使用了volatile。利用jvm對volatile承諾的happen-before原則,完成不加鎖的並發讀,寫。
16. 請說明下java的記憶體模型及其工作流程。
記憶體模型: Java記憶體模型在JVM specification, Java SE 7 Edition, and mainly in the chapters “2.5 Runtime Data Areas” and “2.6 Frames”中有詳細的說明。對象和類的資料存放區在3個不同的記憶體地區:堆(heap space)、方法區(method area)、本地區(native area)。 堆記憶體存放對象以及數組的資料,方法區存放類的資訊(包括類名、方法、欄位)、靜態變數、編譯器編譯後的代碼,本地區包含線程棧、本地方法棧等存放線程。方法區有時被稱為持久代(PermGen),這個主要是因為早期的hotspot使用了方法區來實現持久代,當然這麼做也帶來一些問題,本質上兩者不是一個概念。 所有的對象在執行個體化後的整個運行周期內,都被存放在堆記憶體中。堆記憶體又被劃分成不同的部分:伊甸區(Eden),倖存者地區(Survivor Sapce),老年代(Old Generation Space)。 方法的執行都是伴隨著線程的。原始類型的本地變數以及引用都存放線上程棧中。而引用關聯的對象比如String,都存在在堆中。 堆記憶體同樣被劃分成了多個地區:
  • 包含伊甸(Eden)和倖存者地區(Survivor Sapce)的新生代(Young generation)
  • 老年代(Old Generation)
不同地區的存放的對象擁有不同的生命週期:工作流程: 建立(New)或者短期的對象存放在Eden地區; 倖存的或者中期的對象將會從Eden地區拷貝到Survivor地區; 始終存在或者長期的對象將會從Survivor拷貝到Old Generation; 生命週期來劃分對象,可以消耗很短的時間和CPU做一次小的記憶體回收(GC)。原因是跟C一樣,記憶體的釋放(通過銷毀對象)通過2種不同的GC實現:Young GC、Full GC。 為了檢查所有的對象是否能夠被銷毀,Young GC會標記不能銷毀的對象,經過多次標記後,對象將會被移動到老年代中。
17. 為什麼代碼會重排序?
JMM允許編譯器、運行庫、處理器或緩衝可以有特權定時地在變數的指定記憶體位置存入或取出變數值。例如,編譯器為了最佳化一個迴圈索引變數,可能會選擇把它儲存到一個寄存器中,或者緩衝會延遲到一個更適合的時間,才把一個新的變數值存入主存。所有的這些最佳化是為了協助實現更高的效能。 “重新排序”這個術語用於描述幾種對記憶體操作的類型:
  • 當編譯器不會改變程式的語義時,作為一種最佳化它可以隨意地重新排序某些指令。
  • 在某些情況下,可以允許處理器以顛倒的次序執行一些操作。
  • 通常允許緩衝以與程式寫入變數時所不相同的次序把變數存入主存。
參考列表:
  • 《JAVA2核心技術-卷2:進階特性》
  • 《JAVA並發編程實踐》
  • http://ibruce.info/2013/12/17/how-many-ways-to-create-a-thread-in-java/

JAVA並發總結-基礎篇

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.