freepeople性欧美熟妇, 色戒完整版无删减158分钟hd, 无码精品国产vα在线观看DVD, 丰满少妇伦精品无码专区在线观看,艾栗栗与纹身男宾馆3p50分钟,国产AV片在线观看,黑人与美女高潮,18岁女RAPPERDISSSUBS,国产手机在机看影片

正文內容

java虛擬機詳解-資料下載頁

2025-06-28 08:27本頁面
  

【正文】 60。implementsRunnable{49. Accountaccount。50. intamount。51. 52. publicWithdrawThread(Accountaccount,intamount){53. =account。54. =amount。55. }56. 57. publicvoidrun(){58. for(inti=0。i100000。i++){59. (amount)。60. }61. }62. }63. }第一次執(zhí)行結果為10200,第二次執(zhí)行結果為1060,每次執(zhí)行的結果都是不確定的,因為線程的執(zhí)行順序是不可預見的。這是java同步產生的根源,synchronized關鍵字保證了多個線程對于同步塊是互斥的,synchronized作為一種同步手段,解決java多線程的執(zhí)行有序性和內存可見性,而volatile關鍵字之解決多線程的內存可見性問題。后面將會詳細介紹。synchronized關鍵字 上面說了,java用synchronized關鍵字做為多線程并發(fā)環(huán)境的執(zhí)行有序性的保證手段之一。當一段代碼會修改共享變量,這一段代碼成為互斥區(qū)或臨界區(qū),為了保證共享變量的正確性,synchronized標示了臨界區(qū)。典型的用法如下:Java代碼1. synchronized(鎖){2. 臨界區(qū)代碼3. }為了保證銀行賬戶的安全,可以操作賬戶的方法如下:Java代碼1. publicsynchronizedvoidadd(intnum){2. balance=balance+num。3. }4. publicsynchronizedvoidwithdraw(intnum){5. balance=balancenum。6. }剛才不是說了synchronized的用法是這樣的嗎:Java代碼1. synchronized(鎖){2. 臨界區(qū)代碼3. }那么對于public synchronized void add(int num)這種情況,意味著什么呢?其實這種情況,鎖就是這個方法所在的對象。同理,如果方法是public static synchronized void add(int num),那么鎖就是這個方法所在的class。 理論上,每個對象都可以做為鎖,但一個對象做為鎖時,應該被多個線程共享,這樣才顯得有意義,在并發(fā)環(huán)境下,一個沒有共享的對象作為鎖是沒有意義的。假如有這樣的代碼:Java代碼1. publicclassThreadTest{2. publicvoidtest(){3. Objectlock=newObject()。4. synchronized(lock){5. //dosomething6. }7. }8. }lock變量作為一個鎖存在根本沒有意義,因為它根本不是共享對象,每個線程進來都會執(zhí)行Object lock=new Object()。每個線程都有自己的lock,根本不存在鎖競爭。 每個鎖對象都有兩個隊列,一個是就緒隊列,一個是阻塞隊列,就緒隊列存儲了將要獲得鎖的線程,阻塞隊列存儲了被阻塞的線程,當一個被線程被喚醒(notify)后,才會進入到就緒隊列,等待cpu的調度。,jvm會檢查鎖對象account的就緒隊列是否已經有線程在等待,如果有則表明account的鎖已經被占用了,由于是第一次運行,account的就緒隊列為空,所以線程a獲得了鎖。如果恰好在這個時候,因為線程a已經獲得了鎖還沒有釋放,所以線程b要進入account的就緒隊列,等到得到鎖后才可以執(zhí)行。一個線程執(zhí)行臨界區(qū)代碼過程如下:1 獲得同步鎖2 清空工作內存3 從主存拷貝變量副本到工作內存4 對這些變量計算5 將變量從工作內存寫回到主存6 釋放鎖可見,synchronized既保證了多線程的并發(fā)有序性,又保證了多線程的內存可見性。生產者/消費者模式 生產者/消費者模式其實是一種很經典的線程同步模型,很多時候,并不是光保證多個線程對某共享資源操作的互斥性就夠了,往往多個線程之間都是有協作的。 假設有這樣一種情況,有一個桌子,桌子上面有一個盤子,盤子里只能放一顆雞蛋,A專門往盤子里放雞蛋,如果盤子里有雞蛋,則一直等到盤子里沒雞蛋,B專門從盤子里拿雞蛋,如果盤子里沒雞蛋,則等待直到盤子里有雞蛋。其實盤子就是一個互斥區(qū),每次往盤子放雞蛋應該都是互斥的,A的等待其實就是主動放棄鎖,B等待時還要提醒A放雞蛋。如何讓線程主動釋放鎖很簡單,調用鎖的wait()方法就好。wait方法是從Object來的,所以任意對象都有這個方法??催@個代碼片段:Java代碼1. Objectlock=newObject()。//聲明了一個對象作為鎖2. synchronized(lock){3. balance=balancenum。4. //這里放棄了同步鎖,好不容易得到,又放棄了5. ()。6. }如果一個線程獲得了鎖lock,進入了同步塊,(),那么這個線程會進入到lock的阻塞隊列。()則會通知阻塞隊列的某個線程進入就緒隊列。聲明一個盤子,只能放一個雞蛋Java代碼1. package2. publicclassPlate{3. ListObjecteggs=newArrayListObject()。4. publicsynchronizedObjectgetEgg(){5. if(()==0){6. try{7. wait()。8. }catch(InterruptedExceptione){9. }10. }11. 12. Objectegg=(0)。13. ()。//清空盤子14. notify()。//喚醒阻塞隊列的某線程到就緒隊列15. returnegg。16. }17. 18. publicsynchronizedvoidputEgg(Objectegg){19. If(()0){20. try{21. wait()。22. }catch(InterruptedExceptione){23. }24. }25. (egg)。//往盤子里放雞蛋26. notify()。//喚醒阻塞隊列的某線程到就緒隊列27. }28. }聲明一個Plate對象為plate,被線程A和線程B共享,A專門放雞蛋,B專門拿雞蛋。假設1 開始,()為0,因此順利將雞蛋放到盤子,還執(zhí)行了notify()方法,喚醒鎖的阻塞隊列的線程,此時阻塞隊列還沒有線程。2 ,()不為0,調用wait()方法,自己進入了鎖對象的阻塞隊列。3 此時,來了一個B線程對象,()不為0,順利的拿到了一個雞蛋,還執(zhí)行了notify()方法,喚醒鎖的阻塞隊列的線程,此時阻塞隊列有一個A線程對象,喚醒后,它進入到就緒隊列,就緒隊列也就它一個,因此馬上得到鎖,開始往盤子里放雞蛋,此時盤子是空的,因此放雞蛋成功。4 假設接著來了線程A,就重復2;假設來料線程B,就重復3。整個過程都保證了放雞蛋,拿雞蛋,放雞蛋,拿雞蛋。volatile關鍵字 volatile是java提供的一種同步手段,只不過它是輕量級的同步,為什么這么說,因為volatile只能保證多線程的內存可見性,不能保證多線程的執(zhí)行有序性。而最徹底的同步要保證有序性和可見性,例如synchronized。任何被volatile修飾的變量,都不拷貝副本到工作內存,任何修改都及時寫在主存。因此對于Valatile修飾的變量的修改,所有線程馬上就能看到,但是volatile不能保證對變量的修改是有序的。什么意思呢?假如有這樣的代碼:Java代碼1. publicclassVolatileTest{2. publicvolatileinta。3. publicvoidadd(intcount){4. a=a+count。5. }6. } 當一個VolatileTest對象被多個線程共享,a的值不一定是正確的,因為a=a+count包含了好幾步操作,而此時多個線程的執(zhí)行是無序的,因為沒有任何機制來保證多個線程的執(zhí)行有序性和原子性。volatile存在的意義是,任何線程對a的修改,都會馬上被其他線程讀取到,因為直接操作主存,沒有線程對工作內存和主存的同步。所以,volatile的使用場景是有限的,在有限的一些情形下可以使用 volatile 變量替代鎖。要使 volatile 變量提供理想的線程安全,必須同時滿足下面兩個條件:1)對變量的寫操作不依賴于當前值。2)該變量沒有包含在具有其他變量的不變式中volatile只保證了可見性,所以Volatile適合直接賦值的場景,如Java代碼1. publicclassVolatileTest{2. publicvolatileinta。3. publicvoidsetA(inta){4. =a。5. }6. }在沒有volatile聲明時,多線程環(huán)境下,a的最終值不一定是正確的,=a。涉及到給a賦值和將a同步回主存的步驟,這個順序可能被打亂。如果用volatile聲明了,讀取主存副本到工作內存和同步a到主存的步驟,相當于是一個原子操作。所以簡單來說,volatile適合這種場景:一個變量被多個線程共享,線程直接給這個變量賦值。這是一種很簡單的同步場景,這時候使用volatile的開銷將會非常小。JVM內存管理:深入垃圾收集器與內存分配策略Java與C++之間有一堵由內存動態(tài)分配和垃圾收集技術所圍成的高墻,墻外面的人想進去,墻里面的人卻想出來。概述:  說起垃圾收集(Garbage Collection,下文簡稱GC),大部分人都把這項技術當做Java語言的伴生產物。事實上GC的歷史遠遠比Java來得久遠,在1960年誕生于MIT的Lisp是第一門真正使用內存動態(tài)分配和垃圾收集技術的語言。當Lisp還在胚胎時期,人們就在思考GC需要完成的3件事情:哪些內存需要回收?什么時候回收?怎么樣回收?  經過半個世紀的發(fā)展,目前的內存分配策略與垃圾回收技術已經相當成熟,一切看起來都進入“自動化”的時代,那為什么我們還要去了解GC和內存分配?答案很簡單:當需要排查各種內存溢出、泄漏問題時,當垃圾收集成為系統達到更高并發(fā)量的瓶頸時,我們就需要對這些“自動化”的技術有必要的監(jiān)控、調節(jié)手段。  把時間從1960年撥回現在,回到我們熟悉的Java語言。本文第一章中介紹了Java內存運行時區(qū)域的各個部分,其中程序計數器、VM棧、本地方法棧三個區(qū)域隨線程而生,隨線程而滅;棧中的幀隨著方法進入、退出而有條不紊的進行著出棧入棧操作;每一個幀中分配多少內存基本上是在Class文件生成時就已知的(可能會由JIT動態(tài)晚期編譯進行一些優(yōu)化,但大體上可以認為是編譯期可知的),因此這幾個區(qū)域的內存分配和回收具備很高的確定性,因此在這幾個區(qū)域不需要過多考慮回收的問題。而Java堆和方法區(qū)(包括運行時常量池)則不一樣,我們必須等到程序實際運行期間才能知道會創(chuàng)建哪些對象,這部分內存的分配和回收都是動態(tài)的,我們本文后續(xù)討論中的“內存”分配與回收僅僅指這一部分內存。對象已死?
點擊復制文檔內容
范文總結相關推薦
文庫吧 www.dybbs8.com
備案圖鄂ICP備17016276號-1