java thread
線程狀態(tài)jdk中線程狀態(tài)分為:new,runnable,blocked,waiting,timed_waiting,dead.其中new為剛創(chuàng)建還沒有開始執(zhí)行的狀態(tài),
而runnable狀態(tài)分為可以執(zhí)行和正在執(zhí)行,可以執(zhí)行是因?yàn)榭赡芤萩pu時(shí)間片等。blocked狀態(tài)是指線程在阻塞等待監(jiān)視器的鎖。waiting是指執(zhí)行了Object.wait(),Thread.join()等方法進(jìn)入waiting狀態(tài);timed_waiting是指帶時(shí)間數(shù)的waiting狀態(tài),在時(shí)間到達(dá)之前都是在waiting狀態(tài),dead狀態(tài)是指結(jié)束任務(wù)的線程狀態(tài),再也不能回到runnable狀態(tài)了。
在線程中有waiting set和ready set概念。
當(dāng)一個(gè)對(duì)象執(zhí)行Object.wait()/Object.join(),該線程進(jìn)入waiting set,同時(shí)需要釋放監(jiān)視器的鎖。監(jiān)視器也是一個(gè)普通對(duì)象,在加上一些關(guān)鍵語法后,就能成為監(jiān)視器。
當(dāng)一個(gè)對(duì)象執(zhí)行Object.notify()時(shí),是在waiting set選擇一個(gè)thread進(jìn)入ready set,當(dāng)這個(gè)thread能獲得這個(gè)監(jiān)視器的鎖時(shí)候,就可以進(jìn)入runnable狀態(tài),否則就待在ready set,notifyAll()是通知waiting set里面的所有線程,然后選擇其中的一個(gè),不確定是哪一個(gè),線程的優(yōu)先級(jí)也只是一個(gè)提示和指導(dǎo)。
Object.wait(time)/Object.join(time)方法這些都是在時(shí)間限制到達(dá)之前thread在waiting set,時(shí)間到期之后自動(dòng)進(jìn)入ready set。
Thread.sleep()/Thread.yield()執(zhí)行時(shí)thread都不會(huì)放棄監(jiān)視器的鎖,只是進(jìn)入ready set,Thread.sleep()只是在指定的時(shí)間內(nèi)休眠,得不到任何的資源.Thread.yield()只是提示thread工作差不多完成了,可以讓步給其他Thread,這個(gè)讓步不保證完成,這個(gè)也只對(duì)同等級(jí)的線程有效。
監(jiān)視器
java使用監(jiān)視器來表示同步鎖,在Java里面,任何一個(gè)Object Reference都可以作為同步鎖,只要使用synchronized:
public static final Object signal = new Object();
f1(){
synchronized(signal){
}
}
在jvm內(nèi)部synchronized會(huì)被表示成monitorenter和monitorexit;在一個(gè)時(shí)間段,只有一個(gè)線程能持有monitor,也就是在monitorenter里面,也就達(dá)到了同步的目的.當(dāng)想獲得一個(gè)類變量鎖的時(shí)候,可以使用這個(gè)類的class類。f1(){
synchronized(signal){
}
}
內(nèi)存模型
在jvm規(guī)范中規(guī)定java內(nèi)存模型是java thread work memory和java main memory兩部分
每個(gè)thread一個(gè)thread memory,初始為空,必要時(shí)和main memory通信

規(guī)范規(guī)定了工作內(nèi)存和主內(nèi)存之間通信的8個(gè)行為:use, assign, load, store,read,write, lock, and unlock
use:使用一個(gè)線程工作內(nèi)存中的變量,看成線程的行為
assign:設(shè)置一個(gè)線程工作內(nèi)存中的變量,設(shè)置的值來自線程執(zhí)行引擎,看成線程的行為
read:把主內(nèi)存的值讀到線程工作內(nèi)存當(dāng)中,看成主內(nèi)存的行為
load:在read之后執(zhí)行,真正的把值讀到到工作內(nèi)存當(dāng)中,看成線程的行為
store:保存工作內(nèi)存的值,等下在執(zhí)行write后傳輸給主內(nèi)存,看成線程的行為
write:在store后執(zhí)行,看成主內(nèi)存的行為
lock和unlock是獲取監(jiān)視器鎖和釋放鎖的行為,是第三方synchronized行為
這樣的內(nèi)存模型就會(huì)有問題:
線程工作內(nèi)存是獨(dú)立的,在工作內(nèi)存A的變量被工作內(nèi)存B看到需要經(jīng)過A-->主內(nèi)存-->B的程度,那么什么時(shí)候進(jìn)行工作內(nèi)存到主內(nèi)存的通信呢?
這里需要涉及到緩存一致性模型,即工作內(nèi)存(緩存)什么時(shí)候刷新和讀取主內(nèi)存必須遵循一定的規(guī)則才可以。
java使用釋放一致性模型:在釋放鎖的時(shí)候?qū)懭胫鲀?nèi)存
也就是當(dāng)synchronized表示的方法或者運(yùn)行塊執(zhí)行結(jié)束時(shí)監(jiān)視器鎖釋放后,里面涉及的所有變量(局部變量除外)的值都寫入了主內(nèi)存,當(dāng)變量被其他線程看到的話,其值是最新的。
那么方法或運(yùn)行塊未進(jìn)行同步,可能有兩方面的問題:
1.方法的執(zhí)行順序是未定的
2.即使方法的執(zhí)行順序是相同的,由于工作內(nèi)存的值未寫到主內(nèi)存中也有可能有問題
thread在jvm當(dāng)中執(zhí)行的順序和代碼中看到的順序可能是不一樣的,為了性能優(yōu)化等代碼可能進(jìn)行重排序,所有jmm定義了
線程的執(zhí)行順序模型:happens-before模型,規(guī)則如下:
1.一個(gè)線程當(dāng)中,先出現(xiàn)的指令happens-before后出現(xiàn)的指令
2.構(gòu)造器的里面指令happens-before創(chuàng)建對(duì)象的指令
3.對(duì)于一個(gè)監(jiān)視器,unlock happens-before 想去得鎖的指令
4.對(duì)于volatile的變量,write happens-before read
5.A call to start() on a thread happens-before any actions in the started thread.
6.All actions in a thread happen-before any other thread successfully returns from a
join() on that thread.
happens-before模型保證了JMM內(nèi)存模型的訪問方式。
對(duì)于synchronized我們可以認(rèn)為他符合了上面的第3點(diǎn)
對(duì)于volatile變量,保證了在線程每次修改后馬上反映到主內(nèi)存當(dāng)中,也就是可見性。
對(duì)于synchronized我們可以認(rèn)為他符合了上面的第3點(diǎn)
對(duì)于volatile變量,保證了在線程每次修改后馬上反映到主內(nèi)存當(dāng)中,也就是可見性。
1.All instance fields, static fields and array elements are stored in heap memory.存放在java堆內(nèi)
2.
posted on 2011-09-14 16:53 nod0620 閱讀(640) 評(píng)論(0) 編輯 收藏 所屬分類: java