java的多線程機制

在項目中哼转,經(jīng)常會使用到多線程城舞,例如android本身封裝了handler來進行多線程通信,平時會用到eventbus忙灼,rx這樣的框架來處理匠襟,自己用鎖的時候已經(jīng)很少了,但還是無法完全避免该园。多線程的概念非常好理解酸舍,是為了提高工作效率的一種方法,尤其在現(xiàn)代多cpu多核的計算機下里初,利用好各個資源是非常有必要的啃勉。在android等交互上,為了給用戶良好體驗双妨,不能阻塞用戶交互請求也必須在非ui線程上更新ui淮阐。

線程之間如何正確的通信是我們所關(guān)注的最關(guān)鍵的點。

首先問題在于線程為什么存在同步和通信的問題刁品,這個可以看些java線程內(nèi)存模型的文章泣特,簡單來說原因在于,jvm為每個線程維護了一個私有內(nèi)存挑随,線程間是不能直接通信的状您,他們通過與主存通信完成同步。大家知道兜挨,所謂線程膏孟,其實就是運行在cpu的指令流,就是方法的順序執(zhí)行拌汇。比如說柒桑,方法 f(),在線程1上被調(diào)用的,則這個方法是在線程1上執(zhí)行的担猛,咋一看像句廢話幕垦,其實很多人會陷入某個變量是哪個線程的,比如說handler的理解上傅联,經(jīng)常有說是哪個線程的handler先改,實際上只是他們的loop方法在那個線程調(diào)用了而已,那只是一種易于記憶的說法蒸走,希望大家仔細思考仇奶。這里也同樣說明了另外一個問題,即局部變量是不存在線程同步問題的比驻,因為它的生命周期就是一個方法该溯,即一個局部變量對象只存在于一個線程上岛抄。而相應(yīng)的全局變量是存在線程安全問題的。每個線程內(nèi)存維護了一份該變量的拷貝狈茉,或者說clone更便于理解夫椭,拿mips作為模型舉例來理解,就是比如全局變量A a;會有一個寄存器存儲其的地址氯庆,對應(yīng)地址的內(nèi)存上存有A的信息蹭秋,成員變量值什么的,每個線程用到時都會從主存拷貝一份以上的信息堤撵。但是并不是立刻同步的仁讨,想要立刻寫回可用volatile修飾。(非常不建議的做法)

這里实昨,比如A里的成員變量 int mTv = 1洞豁;在線程1上做了mTv++運算,變成2荒给,這時還未寫回丈挟,但是線程2又做了一遍,則出現(xiàn)了同步問題锐墙,與我們預(yù)期是不一樣的礁哄。這就是我們所要注意和需要解決的問題。

多線程不是java特有的溪北,甚至java是沒有自己的線程模型的,而是直接采用了操作系統(tǒng)的線程模型夺脾。很多維護機制都是從操作系統(tǒng)來的之拨。下面介紹一下大家最常見到的volatile,(就是大家經(jīng)常覺得反正加了保險的那個)咧叭,這里已經(jīng)無數(shù)工程師勸過蚀乔,這個要盡量避免使用,因為至今其使用場景都是非常之低的菲茬,反而會帶來一些其他的問題吉挣。那么它到底什么意思呢。volatile修飾變量婉弹,有強制從主存讀和回寫的作用睬魂,理解起來很簡單,就是用的時候從主存讀镀赌,改變了就往主存回寫氯哮。請注意,它完全不能解決我們的多線程問題I谭稹喉钢!這里就不得不提到另一個人氣更高的關(guān)鍵字:synchronized姆打,這也是jdk5唯一實現(xiàn)鎖的方式(也就是說volatile根本不能算鎖),理解更加簡單肠虽,比如舉個例子幔戏,被其修飾的變量是不會被兩個線程同時調(diào)用改變的,是真真正正的鎖税课,當(dāng)然這是最重的鎖了闲延,大家想一下就知道這種方式是非常保險的,但也是非常不高效的(就是那個最笨的方法)伯复。synchronized可以保證操作是原子性的慨代,volatile是不能保證的。

什么叫原子性呢啸如,大家知道物理學(xué)原子某種程度上算是物體組成基本物質(zhì)了侍匙,可以理解為不可分割的,這里只是便于大家理解關(guān)鍵字概念叮雳,不涉及物理學(xué)知識想暗。強制讀寫就不是一個原子性操作,比如i++帘不,看起來是一步说莫,實際上,要從主存讀寞焙,然后把值拷貝給臨時變量储狭,臨時變量加一賦回i,然后寫回主存捣郊,也就是說辽狈,這整個是可以分割的,是可以進行一半暫停的呛牲,這里我們完成了加法運算還沒寫回主存刮萌,另一個線程調(diào)用i,從主存讀值娘扩,顯然出現(xiàn)了同步問題着茸。線程工作內(nèi)存可以說是主存的一份緩存,為了避免緩存不一致琐旁,volatile需要廢掉此緩存涮阔。除了內(nèi)存緩存之外,在CPU硬件級別也是有緩存的旋膳,即寄存器澎语。假如線程A將變量X由0修改為1的時候,CPU是在其緩存內(nèi)操作,沒有及時回寫到內(nèi)存擅羞,那么JVM是無法X=1是能及時被之后執(zhí)行的線程B看到的尸变,JVM在處理volatile變量的時候,也同樣用了硬件級別的緩存一致性原則减俏。詳細請查閱硬件級別cpu緩存相關(guān)的博客召烂。

volatile是可以防止指令重排的,我覺得這個沒什么特別大意義娃承,大家感興趣可以自己了解一下奏夫,其實就是匯編里那個流水線,可以算是cpu對代碼運行的優(yōu)化历筝,總之建議大家不要隨意使用酗昼。使用可以參閱正確使用 Volatile 變量

synchronized這個用法梳猪,從對方法的修飾上來講麻削,其實可以理解為對對象的修飾,即是每個普通方法加了一個鎖春弥,這個鎖便是對象本身呛哟。所以直接以synchronized (a){}為例,這里是給代碼塊上了一把對象a的鎖匿沛。鎖在Java內(nèi)存模型里在不同機制下對應(yīng)不同的數(shù)據(jù)結(jié)構(gòu)扫责。每個對象都有個長度2個字寬的對象頭(在32位虛擬機里,1字寬是4個字節(jié)逃呼,64位虛擬機里鳖孤,1字寬是8個字節(jié)。如果是數(shù)組對象抡笼,則對象頭是3個字寬淌铐,其中第三個字存儲數(shù)組的長度),這里面存儲了對象的hashcode或鎖信息蔫缸,官方稱它為“Mark Word”,如下圖:

對象頭的最后兩位存儲了鎖的標(biāo)志位际起,01是初始狀態(tài)拾碌,未加鎖,其對象頭里存儲的是對象本身的哈希碼街望,隨著鎖級別的不同校翔,對象頭里存儲不同的內(nèi)容。偏向鎖存儲的是當(dāng)前占用此對象的線程ID灾前;而輕量級則存儲指向線程棧中鎖記錄的指針防症。以上參考Java的多線程機制系列:(三)synchronized的同步原理。一把鎖被一個線程持有,走完鎖住得代碼快鎖會被自動釋放蔫敲,這里也可以在運行一半調(diào)用a.wait()方法釋放鎖饲嗽,阻塞當(dāng)前線程。另一個線程執(zhí)行到某段代碼后希望剛才那個線程繼續(xù)運行奈嘿,則可以調(diào)用a.notify()。當(dāng)?shù)却趏bj上線程收到obj.notify()時,它就能重新獲得obj的獨占鎖疗杉,并繼續(xù)運行象对。注意了,notify()方法是隨機喚起等待在當(dāng)前對象的某一個線程叶圃。

以上可以作為多線程入門的參考袄膏,有時間寫一下高級并發(fā)包的使用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末掺冠,一起剝皮案震驚了整個濱河市沉馆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌赫舒,老刑警劉巖悍及,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異接癌,居然都是意外死亡心赶,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進店門缺猛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來缨叫,“玉大人,你說我怎么就攤上這事荔燎〕芾眩” “怎么了?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵有咨,是天一觀的道長琐簇。 經(jīng)常有香客問我,道長座享,這世上最難降的妖魔是什么婉商? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮渣叛,結(jié)果婚禮上丈秩,老公的妹妹穿的比我還像新娘。我一直安慰自己淳衙,他們只是感情好蘑秽,可當(dāng)我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布饺著。 她就那樣靜靜地躺著,像睡著了一般肠牲。 火紅的嫁衣襯著肌膚如雪幼衰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天埂材,我揣著相機與錄音塑顺,去河邊找鬼。 笑死俏险,一個胖子當(dāng)著我的面吹牛严拒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播竖独,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼裤唠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了莹痢?” 一聲冷哼從身側(cè)響起种蘸,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎竞膳,沒想到半個月后航瞭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡坦辟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年刊侯,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锉走。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡滨彻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出挪蹭,到底是詐尸還是另有隱情亭饵,我是刑警寧澤,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布梁厉,位于F島的核電站辜羊,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏词顾。R本人自食惡果不足惜只冻,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望计技。 院中可真熱鬧,春花似錦山橄、人聲如沸垮媒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽睡雇。三九已至萌衬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間它抱,已是汗流浹背秕豫。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留观蓄,地道東北人混移。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像侮穿,于是被迫代替她去往敵國和親歌径。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,724評論 2 351

推薦閱讀更多精彩內(nèi)容