目錄介紹
- 5.0.0.1 線程池具有什么優(yōu)點(diǎn)和缺點(diǎn)?為什么說(shuō)開(kāi)啟大量的線程,會(huì)降低程序的性能,那么該如何做才能降低性能?
- 5.0.0.3 線程中start和run方法有什么區(qū)別?wait和sleep方法的不同据忘?sleep() 、join()妓笙、yield()有什么區(qū)別若河?
- 5.0.0.4 用Java手寫(xiě)一個(gè)會(huì)導(dǎo)致死鎖的程序,遇到這種問(wèn)題解決方案是什么寞宫?那些場(chǎng)景用到了死鎖機(jī)制萧福?
- 5.0.0.5 ThreadLocal(線程變量副本)這個(gè)類的作用是什么?
- 5.0.0.6 什么是線程安全辈赋?線程安全有那幾個(gè)級(jí)別鲫忍?保障線程安全有哪些手段?ReentrantLock和synchronized的區(qū)別钥屈?
- 5.0.0.7 Volatile和Synchronized各自用途是什么悟民?有哪些不同點(diǎn)?Synchronize在編譯時(shí)如何實(shí)現(xiàn)鎖機(jī)制篷就?
- 5.0.0.8 wait()和sleep()的區(qū)別射亏?各自有哪些使用場(chǎng)景?怎么喚醒一個(gè)阻塞的線程竭业?Thread.sleep(0)的作用是啥智润?
- 5.0.0.9 同步和非同步、阻塞和非阻塞的概念未辆?分別有哪些使用場(chǎng)景窟绷?
- 5.0.1.0 線程的有哪些狀態(tài)?請(qǐng)繪制該狀態(tài)的流程圖咐柜?講一下線程的執(zhí)行生命周期流程兼蜈?線程如果出現(xiàn)了運(yùn)行時(shí)異常會(huì)怎么樣?
- 5.0.1.1 synchronized鎖什么?synchronized同步代碼塊還有同步方法本質(zhì)上鎖住的是誰(shuí)拙友?為什么为狸?
- 5.0.1.2 Volatile實(shí)現(xiàn)原理?一個(gè)int變量遗契,用volatile修飾钥平,多線程去操作++,線程安全嗎?那如何才能保證i++線程安全涉瘾?
- 5.0.1.3 CAS原理是什么?CAS實(shí)現(xiàn)原子操作會(huì)出現(xiàn)什么問(wèn)題捷兰?
- 5.0.1.4 假如有n個(gè)網(wǎng)絡(luò)線程立叛,需要當(dāng)n個(gè)網(wǎng)絡(luò)線程完成之后,再去做數(shù)據(jù)處理贡茅,你會(huì)怎么解決秘蛇?
- 5.0.1.5 Runnable接口和Callable接口的區(qū)別?
- 5.0.1.6 如果提交任務(wù)時(shí)顶考,線程池隊(duì)列已滿赁还,這時(shí)會(huì)發(fā)生什么?線程調(diào)度算法是什么驹沿?
- 5.0.1.7 什么是樂(lè)觀鎖和悲觀鎖艘策?
- 5.0.1.8 線程類的構(gòu)造方法、靜態(tài)塊是被哪個(gè)線程調(diào)用的渊季?同步方法和同步塊朋蔫,哪個(gè)是更好的選擇?同步的范圍越少越好嗎却汉?
- 5.0.1.9 synchonized(this)和synchonized(object)區(qū)別驯妄?Synchronize作用于方法和靜態(tài)方法區(qū)別?
好消息
- 博客筆記大匯總【15年10月到至今】合砂,包括Java基礎(chǔ)及深入知識(shí)點(diǎn)青扔,Android技術(shù)博客,Python學(xué)習(xí)筆記等等翩伪,還包括平時(shí)開(kāi)發(fā)中遇到的bug匯總微猖,當(dāng)然也在工作之余收集了大量的面試題,長(zhǎng)期更新維護(hù)并且修正幻工,持續(xù)完善……開(kāi)源的文件是markdown格式的励两!同時(shí)也開(kāi)源了生活博客,從12年起囊颅,積累共計(jì)500篇[近100萬(wàn)字]当悔,將會(huì)陸續(xù)發(fā)表到網(wǎng)上,轉(zhuǎn)載請(qǐng)注明出處踢代,謝謝盲憎!
- 鏈接地址:https://github.com/yangchong211/YCBlogs
- 如果覺(jué)得好,可以star一下胳挎,謝謝饼疙!當(dāng)然也歡迎提出建議,萬(wàn)事起于忽微慕爬,量變引起質(zhì)變窑眯!所有博客將陸續(xù)開(kāi)源到GitHub屏积!
5.0.0.1 線程池具有什么優(yōu)點(diǎn)和缺點(diǎn)?為什么說(shuō)開(kāi)啟大量的線程,會(huì)降低程序的性能磅甩,那么該如何做才能降低性能炊林?
- 線程池好處:
- 1)降低資源消耗;
- 2)提高相應(yīng)速度卷要;
- 3)提高線程的可管理性渣聚。技術(shù)博客大總結(jié)
- 線程池的實(shí)現(xiàn)原理:
- 當(dāng)提交一個(gè)新任務(wù)到線程池時(shí),判斷核心線程池里的線程是否都在執(zhí)行僧叉。如果不是奕枝,則創(chuàng)建一個(gè)新的線程執(zhí)行任務(wù)。如果核心線程池的線程都在執(zhí)行任務(wù)瓶堕,則進(jìn)入下個(gè)流程隘道。
- 判斷工作隊(duì)列是否已滿。如果未滿捞烟,則將新提交的任務(wù)存儲(chǔ)在這個(gè)工作隊(duì)列里薄声。如果工作隊(duì)列滿了,則進(jìn)入下個(gè)流程题画。
- 判斷線程池是否都處于工作狀態(tài)默辨。如果沒(méi)有,則創(chuàng)建一個(gè)新的工作線程來(lái)執(zhí)行任務(wù)苍息。如果滿了缩幸,則交給飽和策略來(lái)處理這個(gè)任務(wù)。
5.0.0.3 線程中start和run方法有什么區(qū)別竞思?wait和sleep方法的不同表谊?sleep() 、join()盖喷、yield()有什么區(qū)別爆办?
- 線程中start和run方法有什么區(qū)別
- 為什么我們調(diào)用start()方法時(shí)會(huì)執(zhí)行run()方法,為什么我們不能直接調(diào)用run()方法课梳?這是一個(gè)非常經(jīng)典的java多線程面試問(wèn)題距辆。當(dāng)你調(diào)用start()方法時(shí)你將創(chuàng)建新的線程,并且執(zhí)行在run()方法里的代碼暮刃。但是如果你直接調(diào)用run()方法跨算,它不會(huì)創(chuàng)建新的線程也不會(huì)執(zhí)行調(diào)用線程的代碼。
- wait和sleep方法的不同
- 最大的不同是在等待時(shí)wait會(huì)釋放鎖椭懊,而sleep一直持有鎖诸蚕。Wait通常被用于線程間交互,sleep通常被用于暫停執(zhí)行。
- 1背犯、sleep()方法
- 在指定的毫秒數(shù)內(nèi)讓當(dāng)前正在執(zhí)行的線程休眠(暫停執(zhí)行)坏瘩,此操作受到系統(tǒng)計(jì)時(shí)器和調(diào)度程序精度和準(zhǔn)確性的影響。 讓其他線程有機(jī)會(huì)繼續(xù)執(zhí)行媳板,但它并不釋放對(duì)象鎖桑腮。也就是如果有Synchronized同步塊,其他線程仍然不能訪問(wèn)共享數(shù)據(jù)蛉幸。注意該方法要捕獲異常
- 比如有兩個(gè)線程同時(shí)執(zhí)行(沒(méi)有Synchronized),一個(gè)線程優(yōu)先級(jí)為MAX_PRIORITY丛晦,另一個(gè)為MIN_PRIORITY奕纫,如果沒(méi)有Sleep()方法,只有高優(yōu)先級(jí)的線程執(zhí)行完成后烫沙,低優(yōu)先級(jí)的線程才能執(zhí)行匹层;但當(dāng)高優(yōu)先級(jí)的線程sleep(5000)后,低優(yōu)先級(jí)就有機(jī)會(huì)執(zhí)行了锌蓄。
- 總之升筏,sleep()可以使低優(yōu)先級(jí)的線程得到執(zhí)行的機(jī)會(huì),當(dāng)然也可以讓同優(yōu)先級(jí)瘸爽、高優(yōu)先級(jí)的線程有執(zhí)行的機(jī)會(huì)您访。
- 2、yield()方法技術(shù)博客大總結(jié)
- yield()方法和sleep()方法類似剪决,也不會(huì)釋放“鎖標(biāo)志”灵汪,區(qū)別在于,它沒(méi)有參數(shù)柑潦,即yield()方法只是使當(dāng)前線程重新回到可執(zhí)行狀態(tài)享言,所以執(zhí)行yield()的線程有可能在進(jìn)入到可執(zhí)行狀態(tài)后馬上又被執(zhí)行,另外yield()方法只能使同優(yōu)先級(jí)或者高優(yōu)先級(jí)的線程得到執(zhí)行機(jī)會(huì)渗鬼,這也和sleep()方法不同览露。
- 3、join()方法
- Thread的非靜態(tài)方法join()讓一個(gè)線程B“加入”到另外一個(gè)線程A的尾部譬胎。在A執(zhí)行完畢之前差牛,B不能工作。
- Thread t = new MyThread(); t.start(); t.join();保證當(dāng)前線程停止執(zhí)行银择,直到該線程所加入的線程完成為止多糠。然而,如果它加入的線程沒(méi)有存活浩考,則當(dāng)前線程不需要停止夹孔。
- Thread的join()有什么作用?
- Thread的join()的含義是等待該線程終止,即將掛起調(diào)用線程的執(zhí)行搭伤,直到被調(diào)用的對(duì)象完成它的執(zhí)行只怎。比如存在兩個(gè)線程t1和t2,下述代碼表示先啟動(dòng)t1怜俐,直到t1的任務(wù)結(jié)束身堡,才輪到t2啟動(dòng)。
t1.start(); t1.join(); t2.start();
5.0.0.4 用Java手寫(xiě)一個(gè)會(huì)導(dǎo)致死鎖的程序拍鲤,遇到這種問(wèn)題解決方案是什么贴谎?那些場(chǎng)景用到了死鎖機(jī)制?
- 死鎖是怎么一回事
- 線程A和線程B相互等待對(duì)方持有的鎖導(dǎo)致程序無(wú)限死循環(huán)下去季稳。
- 深入理解死鎖的原理
- 兩個(gè)線程里面分別持有兩個(gè)Object對(duì)象:lock1和lock2擅这。這兩個(gè)lock作為同步代碼塊的鎖;
- 線程1的run()方法中同步代碼塊先獲取lock1的對(duì)象鎖景鼠,Thread.sleep(xxx)仲翎,時(shí)間不需要太多,50毫秒差不多了铛漓,然后接著獲取lock2的對(duì)象鎖溯香。這么做主要是為了防止線程1啟動(dòng)一下子就連續(xù)獲得了lock1和lock2兩個(gè)對(duì)象的對(duì)象鎖
- 線程2的run)(方法中同步代碼塊先獲取lock2的對(duì)象鎖,接著獲取lock1的對(duì)象鎖浓恶,當(dāng)然這時(shí)lock1的對(duì)象鎖已經(jīng)被線程1鎖持有玫坛,線程2肯定是要等待線程1釋放lock1的對(duì)象鎖的
5.0.0.5 ThreadLocal(線程變量副本)這個(gè)類的作用是什么?
- ThreadLocal即線程變量
- ThreadLocal為每個(gè)線程維護(hù)一個(gè)本地變量问顷。
- 采用空間換時(shí)間昂秃,它用于線程間的數(shù)據(jù)隔離,它為每個(gè)使用該變量的線程提供獨(dú)立的變量副本杜窄,所以每一個(gè)線程都可以獨(dú)立地改變自己的副本肠骆,而不會(huì)影響其它線程所對(duì)應(yīng)的副本。從線程的角度看塞耕,目標(biāo)變量就象是線程的本地變量蚀腿,這也是類名中“Local”所要表達(dá)的意思。ThreadLocal的實(shí)現(xiàn)是以ThreadLocal對(duì)象為鍵扫外。任意對(duì)象為值得存儲(chǔ)結(jié)構(gòu)莉钙。這個(gè)結(jié)構(gòu)被附帶在線程上,也就是說(shuō)一個(gè)線程可以根據(jù)一個(gè)ThreadLocal對(duì)象查詢到綁定在這個(gè)線程上的一個(gè)值筛谚。
- ThreadLocal類是一個(gè)Map
- ThreadLocal類中維護(hù)一個(gè)Map磁玉,用于存儲(chǔ)每一個(gè)線程的變量副本,Map中元素的鍵為線程對(duì)象驾讲,而值為對(duì)應(yīng)線程的變量副本蚊伞。
- ThreadLocal在Spring中發(fā)揮著巨大的作用席赂,在管理Request作用域中的Bean、事務(wù)管理时迫、任務(wù)調(diào)度颅停、AOP等模塊都出現(xiàn)了它的身影。
- Spring中絕大部分Bean都可以聲明成Singleton作用域掠拳,采用ThreadLocal進(jìn)行封裝癞揉,因此有狀態(tài)的Bean就能夠以singleton的方式在多線程中正常工作了。
- 更多詳細(xì)參考博客:深入研究java.lang.ThreadLocal類
5.0.0.6 什么是線程安全溺欧?線程安全有那幾個(gè)級(jí)別喊熟?保障線程安全有哪些手段?ReentrantLock和synchronized的區(qū)別姐刁?
- 什么是線程安全
- 線程安全就是當(dāng)多個(gè)線程訪問(wèn)一個(gè)對(duì)象時(shí)逊移,如果不用考慮這些線程在運(yùn)行時(shí)環(huán)境下的調(diào)度和交替執(zhí)行,也不需要進(jìn)行額外的同步龙填,或者在調(diào)用方進(jìn)行任何其他的協(xié)調(diào)操作,調(diào)用這個(gè)對(duì)象的行為都可以獲得正確的結(jié)果拐叉,那這個(gè)對(duì)象是線程安全的岩遗。
- 線程安全也是有幾個(gè)級(jí)別
- 技術(shù)博客大總結(jié)
- 不可變:
- 像String、Integer凤瘦、Long這些宿礁,都是final類型的類,任何一個(gè)線程都改變不了它們的值蔬芥,要改變除非新創(chuàng)建一個(gè)梆靖,因此這些不可變對(duì)象不需要任何同步手段就可以直接在多線程環(huán)境下使用
- 絕對(duì)線程安全
- 不管運(yùn)行時(shí)環(huán)境如何,調(diào)用者都不需要額外的同步措施笔诵。要做到這一點(diǎn)通常需要付出許多額外的代價(jià)返吻,Java中標(biāo)注自己是線程安全的類,實(shí)際上絕大多數(shù)都不是線程安全的乎婿,不過(guò)絕對(duì)線程安全的類测僵,Java中也有,比方說(shuō)CopyOnWriteArrayList谢翎、CopyOnWriteArraySet
- 相對(duì)線程安全
- 相對(duì)線程安全也就是我們通常意義上所說(shuō)的線程安全捍靠,像Vector這種,add森逮、remove方法都是原子操作榨婆,不會(huì)被打斷,但也僅限于此褒侧,如果有個(gè)線程在遍歷某個(gè)Vector良风、有個(gè)線程同時(shí)在add這個(gè)Vector谊迄,99%的情況下都會(huì)出現(xiàn)ConcurrentModificationException,也就是fail-fast機(jī)制拖吼。
- 線程非安全技術(shù)博客大總結(jié)
- ArrayList鳞上、LinkedList、HashMap等都是線程非安全的類.
- 保障線程安全有哪些手段吊档。保證線程安全可從多線程三特性出發(fā):
- 原子性(Atomicity):?jiǎn)蝹€(gè)或多個(gè)操作是要么全部執(zhí)行篙议,要么都不執(zhí)行
- Lock:保證同時(shí)只有一個(gè)線程能拿到鎖,并執(zhí)行申請(qǐng)鎖和釋放鎖的代碼
- synchronized:對(duì)線程加獨(dú)占鎖怠硼,被它修飾的類/方法/變量只允許一個(gè)線程訪問(wèn)
- 可見(jiàn)性(Visibility):當(dāng)一個(gè)線程修改了共享變量的值鬼贱,其他線程能夠立即得知這個(gè)修改
- volatile:保證新值能立即同步到主內(nèi)存,且每次使用前立即從主內(nèi)存刷新香璃;
- synchronized:在釋放鎖之前會(huì)將工作內(nèi)存新值更新到主存中
- 有序性(Ordering):程序代碼按照指令順序執(zhí)行
- volatile: 本身就包含了禁止指令重排序的語(yǔ)義
- synchronized:保證一個(gè)變量在同一個(gè)時(shí)刻只允許一條線程對(duì)其進(jìn)行l(wèi)ock操作这难,使得持有同一個(gè)鎖的兩個(gè)同步塊只能串行地進(jìn)入
- 原子性(Atomicity):?jiǎn)蝹€(gè)或多個(gè)操作是要么全部執(zhí)行篙议,要么都不執(zhí)行
- ReentrantLock和synchronized的區(qū)別
- ReentrantLock與synchronized的不同在于ReentrantLock:
- 等待可中斷:當(dāng)持有鎖的線程長(zhǎng)期不釋放鎖的時(shí)候,正在等待的線程可以選擇放棄等待葡秒,改為處理其他事情姻乓。
- 公平鎖:多個(gè)線程在等待同一個(gè)鎖時(shí),必須按照申請(qǐng)鎖的時(shí)間順序來(lái)依次獲得鎖眯牧。而synchronized是非公平的蹋岩,即在鎖被釋放時(shí),任何一個(gè)等待鎖的線程都有機(jī)會(huì)獲得鎖学少。ReentrantLock默認(rèn)情況下也是非公平的剪个,但可以通過(guò)帶布爾值的構(gòu)造函數(shù)改用公平鎖。
- 鎖綁定多個(gè)條件:一個(gè)ReentrantLock對(duì)象可以通過(guò)多次調(diào)用newCondition()同時(shí)綁定多個(gè)Condition對(duì)象版确。而在synchronized中扣囊,鎖對(duì)象wait()和notify()或notifyAl()只能實(shí)現(xiàn)一個(gè)隱含的條件,若要和多于一個(gè)的條件關(guān)聯(lián)不得不額外地添加一個(gè)鎖绒疗。
- Synchronized是悲觀鎖機(jī)制侵歇,獨(dú)占鎖。而Locks.ReentrantLock是忌堂,每次不加鎖而是假設(shè)沒(méi)有沖突而去完成某項(xiàng)操作盒至,如果因?yàn)闆_突失敗就重試,直到成功為止士修。
- ReentrantLock適用場(chǎng)景
- 某個(gè)線程在等待一個(gè)鎖的控制權(quán)的這段時(shí)間需要中斷
- 需要分開(kāi)處理一些wait-notify枷遂,ReentrantLock里面的Condition應(yīng)用,能夠控制notify哪個(gè)線程棋嘲,鎖可以綁定多個(gè)條件酒唉。
- 具有公平鎖功能,每個(gè)到來(lái)的線程都將排隊(duì)等候沸移。
- 更多詳細(xì)參考博客:Lock與synchronized 的區(qū)別
- ReentrantLock與synchronized的不同在于ReentrantLock:
5.0.0.7 Volatile和Synchronized各自用途是什么痪伦?有哪些不同點(diǎn)侄榴?Synchronize在編譯時(shí)如何實(shí)現(xiàn)鎖機(jī)制?
- Volatile和Synchronized各自用途是什么网沾?有哪些不同點(diǎn)癞蚕?
- 1 粒度不同,前者針對(duì)變量 辉哥,后者鎖對(duì)象和類
- 2 syn阻塞桦山,volatile線程不阻塞
- 3 syn保證三大特性,volatile不保證原子性
- 4 syn編譯器優(yōu)化醋旦,volatile不優(yōu)化 volatile具備兩種特性:
- 1.保證此變量對(duì)所有線程的可見(jiàn)性恒水,指一條線程修改了這個(gè)變量的值,新值對(duì)于其他線程來(lái)說(shuō)是可見(jiàn)的饲齐,但并不是多線程安全的钉凌。
- 2.禁止指令重排序優(yōu)化。
- Volatile如何保證內(nèi)存可見(jiàn)性:
- 1.當(dāng)寫(xiě)一個(gè)volatile變量時(shí)捂人,JMM會(huì)把該線程對(duì)應(yīng)的本地內(nèi)存中的共享變量刷新到主內(nèi)存御雕。
- 2.當(dāng)讀一個(gè)volatile變量時(shí),JMM會(huì)把該線程對(duì)應(yīng)的本地內(nèi)存置為無(wú)效滥搭。線程接下來(lái)將從主內(nèi)存中讀取共享變量饮笛。
- 同步:就是一個(gè)任務(wù)的完成需要依賴另外一個(gè)任務(wù),只有等待被依賴的任務(wù)完成后论熙,依賴任務(wù)才能完成。
- 異步:不需要等待被依賴的任務(wù)完成摄狱,只是通知被依賴的任務(wù)要完成什么工作脓诡,只要自己任務(wù)完成了就算完成了,被依賴的任務(wù)是否完成會(huì)通知回來(lái)媒役。(異步的特點(diǎn)就是通知)祝谚。 打電話和發(fā)短信來(lái)比喻同步和異步操作。
- 阻塞:CPU停下來(lái)等一個(gè)慢的操作完成以后酣衷,才會(huì)接著完成其他的工作交惯。
- 非阻塞:非阻塞就是在這個(gè)慢的執(zhí)行時(shí),CPU去做其他工作穿仪,等這個(gè)慢的完成后席爽,CPU才會(huì)接著完成后續(xù)的操作。
- 非阻塞會(huì)造成線程切換增加啊片,增加CPU的使用時(shí)間能不能補(bǔ)償系統(tǒng)的切換成本需要考慮只锻。
- Synchronize在編譯時(shí)如何實(shí)現(xiàn)鎖機(jī)制?
- Synchronized進(jìn)過(guò)編譯紫谷,會(huì)在同步塊的前后分別形成monitorenter和monitorexit這個(gè)兩個(gè)字節(jié)碼指令齐饮。在執(zhí)行monitorenter指令時(shí)捐寥,首先要嘗試獲取對(duì)象鎖。如果這個(gè)對(duì)象沒(méi)被鎖定祖驱,或者當(dāng)前線程已經(jīng)擁有了那個(gè)對(duì)象鎖握恳,把鎖的計(jì)算器加1,相應(yīng)的捺僻,在執(zhí)行monitorexit指令時(shí)會(huì)將鎖計(jì)算器就減1乡洼,當(dāng)計(jì)算器為0時(shí),鎖就被釋放了陵像。如果獲取對(duì)象鎖失敗就珠,那當(dāng)前線程就要阻塞,直到對(duì)象鎖被另一個(gè)線程釋放為止醒颖。
5.0.0.8 wait()和sleep()的區(qū)別妻怎?各自有哪些使用場(chǎng)景?怎么喚醒一個(gè)阻塞的線程泞歉?Thread.sleep(0)的作用是啥逼侦?
- sleep來(lái)自Thread類孵睬,和wait來(lái)自O(shè)bject類
- 調(diào)用sleep()方法的過(guò)程中播揪,線程不會(huì)釋放對(duì)象鎖。而調(diào)用wait方法線程會(huì)釋放對(duì)象鎖
- sleep睡眠后不出讓系統(tǒng)資源彻况,wait讓出系統(tǒng)資源其他線程可以占用CPU
- sleep(milliseconds)需要指定一個(gè)睡眠時(shí)間挺庞,時(shí)間一到會(huì)自動(dòng)喚醒
- 通俗解釋
- Java程序中wait 和 sleep都會(huì)造成某種形式的暫停晰赞,它們可以滿足不同的需要。wait()方法用于線程間通信选侨,如果等待條件為真且其它線程被喚醒時(shí)它會(huì)釋放鎖掖鱼,而 sleep()方法僅僅釋放CPU資源或者讓當(dāng)前線程停止執(zhí)行一段時(shí)間,但不會(huì)釋放鎖援制。
- 怎么喚醒一個(gè)阻塞的線程戏挡?
- 如果線程是因?yàn)檎{(diào)用了wait()、sleep()或者join()方法而導(dǎo)致的阻塞晨仑,可以中斷線程褐墅,并且通過(guò)拋出InterruptedException來(lái)喚醒它妥凳;如果線程遇到了IO阻塞答捕,無(wú)能為力,因?yàn)镮O是操作系統(tǒng)實(shí)現(xiàn)的晌缘,Java代碼并沒(méi)有辦法直接接觸到操作系統(tǒng)。
- 技術(shù)博客大總結(jié)
- Thread.sleep(0)的作用是啥磷箕?
- 由于Java采用搶占式的線程調(diào)度算法,因此可能會(huì)出現(xiàn)某條線程常常獲取到CPU控制權(quán)的情況芒填,為了讓某些優(yōu)先級(jí)比較低的線程也能獲取到CPU控制權(quán)空繁,可以使用Thread.sleep(0)手動(dòng)觸發(fā)一次操作系統(tǒng)分配時(shí)間片的操作,這也是平衡CPU控制權(quán)的一種操作闷祥。
5.0.0.9 同步和非同步傲诵、阻塞和非阻塞的概念?分別有哪些使用場(chǎng)景拴竹?
- 同步和非同步
- 同步和異步體現(xiàn)的是消息的通知機(jī)制:所謂同步悟衩,方法A調(diào)用方法B后必須等到方法B返回結(jié)果才能繼續(xù)后面的操作;所謂異步栓拜,方法A調(diào)用方法B后可讓方法B在調(diào)用結(jié)束后通過(guò)回調(diào)等方式通知方法A
- 阻塞和非阻塞
- 阻塞和非阻塞側(cè)重于等待消息時(shí)的狀態(tài):所謂阻塞座泳,就是在結(jié)果返回之前讓當(dāng)前線程掛起;所謂非阻塞幕与,就是在等待時(shí)可做其他事情钳榨,通過(guò)輪詢?nèi)ピ儐?wèn)是否已返回結(jié)果
5.0.1.0 線程的有哪些狀態(tài)?請(qǐng)繪制該狀態(tài)的流程圖纽门?講一下線程的執(zhí)行生命周期流程?線程如果出現(xiàn)了運(yùn)行時(shí)異常會(huì)怎么樣?
- 在任意一個(gè)時(shí)間點(diǎn)营罢,一個(gè)線程只能有且只有其中的一種狀態(tài)
- 新建(New):線程創(chuàng)建后尚未啟動(dòng)
- 技術(shù)博客大總結(jié)
- 運(yùn)行(Runable):包括正在執(zhí)行(Running)和等待著CPU為它分配執(zhí)行時(shí)間(Ready)兩種
無(wú)限期等待(Waiting):該線程不會(huì)被分配CPU執(zhí)行時(shí)間赏陵,要等待被其他線程顯式地喚醒。以下方法會(huì)讓線程陷入無(wú)限期等待狀態(tài):
沒(méi)有設(shè)置Timeout參數(shù)的Object.wait() 沒(méi)有設(shè)置Timeout參數(shù)的Thread.join() LockSupport.park()
- 限期等待(Timed Waiting):該線程不會(huì)被分配CPU執(zhí)行時(shí)間饲漾,但在一定時(shí)間后會(huì)被系統(tǒng)自動(dòng)喚醒蝙搔。以下方法會(huì)讓線程進(jìn)入限期等待狀態(tài):
Thread.sleep() 設(shè)置了Timeout參數(shù)的Object.wai() 設(shè)置了Timeout參數(shù)的Thread.join() LockSupport.parkNanos() LockSupport.parkUntil()
- 阻塞(Blocked):線程被阻塞。和等待狀態(tài)不同的是考传,阻塞狀態(tài)表示在等待獲取到一個(gè)排他鎖吃型,在另外一個(gè)線程放棄這個(gè)鎖的時(shí)候發(fā)生;而等待狀態(tài)表示在等待一段時(shí)間或者喚醒動(dòng)作的發(fā)生僚楞,在程序等待進(jìn)入同步區(qū)域的時(shí)候發(fā)生勤晚。
- 結(jié)束(Terminated):線程已經(jīng)結(jié)束執(zhí)行
- 繪制該狀態(tài)的流程圖
- 線程如果出現(xiàn)了運(yùn)行時(shí)異常會(huì)怎么樣?
- 如果這個(gè)異常沒(méi)有被捕獲的話枉层,這個(gè)線程就停止執(zhí)行了。另外重要的一點(diǎn)是:如果這個(gè)線程持有某個(gè)某個(gè)對(duì)象的監(jiān)視器赐写,那么這個(gè)對(duì)象監(jiān)視器會(huì)被立即釋放
5.0.1.1 synchronized鎖什么鸟蜡?synchronized同步代碼塊還有同步方法本質(zhì)上鎖住的是誰(shuí)?為什么泣矛?
- synchronized鎖什么
- 對(duì)于普通同步方法您朽,鎖是當(dāng)前實(shí)例對(duì)象;
- 對(duì)于靜態(tài)同步方法魂奥,鎖是當(dāng)前類的Class對(duì)象;
- 對(duì)于同步方法塊哈蝇,鎖是括號(hào)中配置的對(duì)象炮赦;
- 當(dāng)一個(gè)線程試圖訪問(wèn)同步代碼塊時(shí),它首先必須得到鎖剧防,退出或拋出異常時(shí)必須釋放鎖。synchronized用的鎖是存在Java對(duì)象頭里的MarkWord鸡挠,通常是32bit或者64bit鞋囊,其中最后2bit表示鎖標(biāo)志位溜腐。
- 本質(zhì)上鎖住的是對(duì)象。
- 在java虛擬機(jī)中望众,每個(gè)對(duì)象和類在邏輯上都和一個(gè)監(jiān)視器相關(guān)聯(lián),synchronized本質(zhì)上是對(duì)一個(gè)對(duì)象監(jiān)視器的獲取甘耿。當(dāng)執(zhí)行同步代碼塊或同步方法時(shí)佳恬,執(zhí)行方法的線程必須先獲得該對(duì)象的監(jiān)視器,才能進(jìn)入同步代碼塊或同步方法倾剿;而沒(méi)有獲取到的線程將會(huì)進(jìn)入阻塞隊(duì)列,直到成功獲取對(duì)象監(jiān)視器的線程執(zhí)行結(jié)束并釋放鎖后,才會(huì)喚醒阻塞隊(duì)列的線程涵妥,使其重新嘗試對(duì)對(duì)象監(jiān)視器的獲取蓬网。
5.0.1.2 Volatile實(shí)現(xiàn)原理吵取?一個(gè)int變量皮官,用volatile修飾,多線程去操作++剪撬,線程安全嗎馍佑?那如何才能保證i++線程安全拭荤?
- volatile的作用和原理
- Java代碼在編譯后會(huì)變成Java字節(jié)碼,字節(jié)碼被類加載器加載到JVM里歇终,JVM執(zhí)行字節(jié)碼评凝,最終需要轉(zhuǎn)化為匯編指令在CPU上執(zhí)行。
- volatile是輕量級(jí)的synchronized(volatile不會(huì)引起線程上下文的切換和調(diào)度)翎碑,它在多處理器開(kāi)發(fā)中保證了共享變量的“可見(jiàn)性”日杈∧鹫ǎ可見(jiàn)性的意思是當(dāng)一個(gè)線程修改一個(gè)共享變量時(shí)填硕,另外一個(gè)線程能讀到這個(gè)修改的值。
- 由于內(nèi)存訪問(wèn)速度遠(yuǎn)不及CPU處理速度恋拍,為了提高處理速度,處理器不直接和內(nèi)存進(jìn)行通信僵娃,而是先將系統(tǒng)內(nèi)存的數(shù)據(jù)讀到內(nèi)部緩存后在進(jìn)行操作,但操作完不知道何時(shí)會(huì)寫(xiě)到內(nèi)存骤素。普通共享變量被修改之后痕檬,什么時(shí)候被寫(xiě)入主存是不確定的梦谜,當(dāng)其他線程去讀取時(shí),此時(shí)內(nèi)存中可能還是原來(lái)的舊值耸棒,因此無(wú)法保證可見(jiàn)性单山。如果對(duì)聲明了volatile的變量進(jìn)行寫(xiě)操作,JVM就會(huì)想處理器發(fā)送一條Lock前綴的指令躏升,表示將當(dāng)前處理器緩存行的數(shù)據(jù)寫(xiě)回到系統(tǒng)內(nèi)存。
- 一個(gè)int變量佃却,用volatile修飾,多線程去操作++灶泵,線程安全嗎
- 技術(shù)博客大總結(jié)
- 不安全
- 案例代碼,至于打印結(jié)果就不展示呢
- volatile只能保證可見(jiàn)性惶洲,并不能保證原子性。
- i++實(shí)際上會(huì)被分成多步完成:
- 1)獲取i的值币呵;
- 2)執(zhí)行i+1余赢;
- 3)將結(jié)果賦值給i耘分。
- volatile只能保證這3步不被重排序,多線程情況下计盒,可能兩個(gè)線程同時(shí)獲取i,執(zhí)行i+1咕村,然后都賦值結(jié)果2,實(shí)際上應(yīng)該進(jìn)行兩次+1操作批钠。
private volatile int a = 0; for (int x=0 ; x<=100 ; x++){ new Thread(new Runnable() { @Override public void run() { a++; Log.e("小楊逗比Thread-------------",""+a); } }).start(); }
- 如何才能保證i++線程安全
- 可以使用java.util.concurrent.atomic包下的原子類,如AtomicInteger踩窖。其實(shí)現(xiàn)原理是采用CAS自旋操作更新值晨横。
for (int x=0 ; x<=100 ; x++){ new Thread(new Runnable() { @Override public void run() { AtomicInteger atomicInteger = new AtomicInteger(a++); int i = atomicInteger.get(); Log.e("小楊逗比Thread-------------",""+i); } }).start(); }
5.0.1.3 CAS原理是什么洋腮?CAS實(shí)現(xiàn)原子操作會(huì)出現(xiàn)什么問(wèn)題?
- CAS原理是什么
- CAS即compare and swap的縮寫(xiě)手形,中文翻譯成比較并交換啥供。CAS有3個(gè)操作數(shù),內(nèi)存值V库糠,舊的預(yù)期值A(chǔ)伙狐,要修改的新值B。當(dāng)且僅當(dāng)預(yù)期值A(chǔ)和內(nèi)存值V相同時(shí),將內(nèi)存值V修改為B,否則什么都不做须蜗。自旋就是不斷嘗試CAS操作直到成功為止蛉腌。
- CAS實(shí)現(xiàn)原子操作會(huì)出現(xiàn)什么問(wèn)題
- ABA問(wèn)題忘蟹。因?yàn)镃AS需要在操作之的時(shí)候嚼松,檢查值有沒(méi)有發(fā)生變化锨亏,如果沒(méi)有發(fā)生變化則更新爱葵,但是如果一個(gè)值原來(lái)是A月劈,變成腊凶,有變成A,那么使用CAS進(jìn)行檢查時(shí)會(huì)發(fā)現(xiàn)它的值沒(méi)有發(fā)生變化挖炬,但實(shí)際上發(fā)生了變化敞曹。ABA問(wèn)題可以通過(guò)添加版本號(hào)來(lái)解決。Java 1.5開(kāi)始取胎,JDK的Atomic包里提供了一個(gè)類AtomicStampedReference來(lái)解決ABA問(wèn)題俐芯。
- 循環(huán)時(shí)間長(zhǎng)開(kāi)銷大。pause指令優(yōu)化痴腌。
- 只能保證一個(gè)共享變量的原子操作胀糜±ǖ蹋可以合并成一個(gè)對(duì)象進(jìn)行CAS操作恢口。
5.0.1.4 假如有n個(gè)網(wǎng)絡(luò)線程狡忙,需要當(dāng)n個(gè)網(wǎng)絡(luò)線程完成之后录粱,再去做數(shù)據(jù)處理蔬螟,你會(huì)怎么解決?
- 多線程同步的問(wèn)題汽畴。這種情況可以可以使用thread.join()旧巾;join方法會(huì)阻塞直到thread線程終止才返回。更復(fù)雜一點(diǎn)的情況也可以使用CountDownLatch整袁,CountDownLatch的構(gòu)造接收一個(gè)int參數(shù)作為計(jì)數(shù)器菠齿,每次調(diào)用countDown方法計(jì)數(shù)器減一。做數(shù)據(jù)處理的線程調(diào)用await方法阻塞直到計(jì)數(shù)器為0時(shí)坐昙。
5.0.1.5 Runnable接口和Callable接口的區(qū)別绳匀?
- Runnable接口和Callable接口的區(qū)別
- Runnable接口中的run()方法的返回值是void,它做的事情只是純粹地去執(zhí)行run()方法中的代碼而已炸客;Callable接口中的call()方法是有返回值的疾棵,是一個(gè)泛型,和Future痹仙、FutureTask配合可以用來(lái)獲取異步執(zhí)行的結(jié)果是尔。
- 這其實(shí)是很有用的一個(gè)特性,因?yàn)槎嗑€程相比單線程更難开仰、更復(fù)雜的一個(gè)重要原因就是因?yàn)槎嗑€程充滿著未知性拟枚,某條線程是否執(zhí)行了?某條線程執(zhí)行了多久众弓?某條線程執(zhí)行的時(shí)候我們期望的數(shù)據(jù)是否已經(jīng)賦值完畢恩溅?無(wú)法得知,我們能做的只是等待這條多線程的任務(wù)執(zhí)行完畢而已谓娃。而Callable+Future/FutureTask卻可以獲取多線程運(yùn)行的結(jié)果脚乡,可以在等待時(shí)間太長(zhǎng)沒(méi)獲取到需要的數(shù)據(jù)的情況下取消該線程的任務(wù),真的是非常有用滨达。
5.0.1.6 如果提交任務(wù)時(shí)奶稠,線程池隊(duì)列已滿,這時(shí)會(huì)發(fā)生什么捡遍?線程調(diào)度算法是什么锌订?
- 如果提交任務(wù)時(shí),線程池隊(duì)列已滿画株,這時(shí)會(huì)發(fā)生什么辆飘?
- 如果使用的是無(wú)界隊(duì)列LinkedBlockingQueue涩搓,也就是無(wú)界隊(duì)列的話,沒(méi)關(guān)系劈猪,繼續(xù)添加任務(wù)到阻塞隊(duì)列中等待執(zhí)行昧甘,因?yàn)長(zhǎng)inkedBlockingQueue可以近乎認(rèn)為是一個(gè)無(wú)窮大的隊(duì)列,可以無(wú)限存放任務(wù)
- 技術(shù)博客大總結(jié)
- 如果使用的是有界隊(duì)列比如ArrayBlockingQueue战得,任務(wù)首先會(huì)被添加到ArrayBlockingQueue中充边,ArrayBlockingQueue滿了,會(huì)根據(jù)maximumPoolSize的值增加線程數(shù)量常侦,如果增加了線程數(shù)量還是處理不過(guò)來(lái)浇冰,ArrayBlockingQueue繼續(xù)滿,那么則會(huì)使用拒絕策略RejectedExecutionHandler處理滿了的任務(wù)聋亡,默認(rèn)是AbortPolicy
- 線程調(diào)度算法是什么肘习?
- 搶占式。一個(gè)線程用完CPU之后坡倔,操作系統(tǒng)會(huì)根據(jù)線程優(yōu)先級(jí)漂佩、線程饑餓情況等數(shù)據(jù)算出一個(gè)總的優(yōu)先級(jí)并分配下一個(gè)時(shí)間片給某個(gè)線程執(zhí)行。
5.0.1.7 什么是樂(lè)觀鎖和悲觀鎖罪塔?
- 什么是樂(lè)觀鎖和悲觀鎖投蝉?
- 樂(lè)觀鎖:就像它的名字一樣,對(duì)于并發(fā)間操作產(chǎn)生的線程安全問(wèn)題持樂(lè)觀狀態(tài)征堪,樂(lè)觀鎖認(rèn)為競(jìng)爭(zhēng)不總是會(huì)發(fā)生瘩缆,因此它不需要持有鎖,將比較-替換這兩個(gè)動(dòng)作作為一個(gè)原子操作嘗試去修改內(nèi)存中的變量佃蚜,如果失敗則表示發(fā)生沖突庸娱,那么就應(yīng)該有相應(yīng)的重試邏輯。
- 悲觀鎖:還是像它的名字一樣谐算,對(duì)于并發(fā)間操作產(chǎn)生的線程安全問(wèn)題持悲觀狀態(tài)熟尉,悲觀鎖認(rèn)為競(jìng)爭(zhēng)總是會(huì)發(fā)生,因此每次對(duì)某資源進(jìn)行操作時(shí)氯夷,都會(huì)持有一個(gè)獨(dú)占的鎖臣樱,就像synchronized靶擦,直接上了鎖就操作資源腮考。
5.0.1.8 線程類的構(gòu)造方法、靜態(tài)塊是被哪個(gè)線程調(diào)用的玄捕?同步方法和同步塊踩蔚,哪個(gè)是更好的選擇?同步的范圍越少越好嗎枚粘?
- 線程類的構(gòu)造方法馅闽、靜態(tài)塊是被哪個(gè)線程調(diào)用的?
- 線程類的構(gòu)造方法、靜態(tài)塊是被new這個(gè)線程類所在的線程所調(diào)用的福也,而run方法里面的代碼才是被線程自身所調(diào)用的局骤。
- 舉個(gè)例子
- 假設(shè)Thread2中new了Thread1,main函數(shù)中new了Thread2暴凑,那么:
- Thread2的構(gòu)造方法峦甩、靜態(tài)塊是main線程調(diào)用的,Thread2的run()方法是Thread2自己調(diào)用的
- Thread1的構(gòu)造方法现喳、靜態(tài)塊是Thread2調(diào)用的凯傲,Thread1的run()方法是Thread1自己調(diào)用的
- 假設(shè)Thread2中new了Thread1,main函數(shù)中new了Thread2暴凑,那么:
- 同步方法和同步塊,哪個(gè)是更好的選擇嗦篱?
- 同步塊冰单,這意味著同步塊之外的代碼是異步執(zhí)行的,這比同步整個(gè)方法更提升代碼的效率灸促。請(qǐng)知道一條原則:同步的范圍越小越好诫欠。
- 技術(shù)博客大總結(jié)
- 同步的范圍越少越好嗎?
- 是的浴栽。雖說(shuō)同步的范圍越少越好呕诉,但是在Java虛擬機(jī)中還是存在著一種叫做鎖粗化的優(yōu)化方法,這種方法就是把同步范圍變大吃度。這是有用的甩挫,比方說(shuō)StringBuffer,它是一個(gè)線程安全的類椿每,自然最常用的append()方法是一個(gè)同步方法伊者,我們寫(xiě)代碼的時(shí)候會(huì)反復(fù)append字符串,這意味著要進(jìn)行反復(fù)的加鎖->解鎖间护,這對(duì)性能不利亦渗,因?yàn)檫@意味著Java虛擬機(jī)在這條線程上要反復(fù)地在內(nèi)核態(tài)和用戶態(tài)之間進(jìn)行切換,因此Java虛擬機(jī)會(huì)將多次append方法調(diào)用的代碼進(jìn)行一個(gè)鎖粗化的操作汁尺,將多次的append的操作擴(kuò)展到append方法的頭尾法精,變成一個(gè)大的同步塊,這樣就減少了加鎖-->解鎖的次數(shù)痴突,有效地提升了代碼執(zhí)行的效率搂蜓。
5.0.1.9 synchonized(this)和synchonized(object)區(qū)別?Synchronize作用于方法和靜態(tài)方法區(qū)別辽装?
- synchonized(this)和synchonized(object)區(qū)別技術(shù)博客大總結(jié)
- 其實(shí)并沒(méi)有很大的區(qū)別帮碰,synchonized(object)本身就包含synchonized(this)這種情況,使用的場(chǎng)景都是對(duì)一個(gè)代碼塊進(jìn)行加鎖拾积,效率比直接在方法名上加synchonized高一些(下面分析)殉挽,唯一的區(qū)別就是對(duì)象的不同丰涉。
- 對(duì)synchronized(this)的一些理解
- 一、當(dāng)兩個(gè)并發(fā)線程訪問(wèn)同一個(gè)對(duì)象object中的這個(gè)synchronized(this)同步代碼塊時(shí)斯碌,一個(gè)時(shí)間內(nèi)只能有一個(gè)線程得到執(zhí)行一死。另一個(gè)線程必須等待當(dāng)前線程執(zhí)行完這個(gè)代碼塊以后才能執(zhí)行該代碼塊。
- 二傻唾、然而摘符,當(dāng)一個(gè)線程訪問(wèn)object的一個(gè)synchronized(this)同步代碼塊時(shí),另一個(gè)線程仍然可以訪問(wèn)該object中的非synchronized(this)同步代碼塊策吠。
- 三逛裤、尤其關(guān)鍵的是,當(dāng)一個(gè)線程訪問(wèn)object的一個(gè)synchronized(this)同步代碼塊時(shí)猴抹,其他線程對(duì)object中所有其它synchronized(this)同步代碼塊的訪問(wèn)將被阻塞带族。
- 四、當(dāng)一個(gè)線程訪問(wèn)object的一個(gè)synchronized(this)同步代碼塊時(shí)蟀给,它就獲得了這個(gè)object的對(duì)象鎖蝙砌。結(jié)果,其它線程對(duì)該object對(duì)象所有同步代碼部分的訪問(wèn)都被暫時(shí)阻塞跋理。
- Synchronize作用于方法和靜態(tài)方法區(qū)別
- 測(cè)試代碼如下所示
private void test() { final TestSynchronized test1 = new TestSynchronized(); final TestSynchronized test2 = new TestSynchronized(); Thread t1 = new Thread(new Runnable() { @Override public void run() { test1.method01("a"); //test1.method02("a"); } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { test2.method01("b"); //test2.method02("a"); } }); t1.start(); t2.start(); } private static class TestSynchronized{ private int num1; public synchronized void method01(String arg) { try { if("a".equals(arg)){ num1 = 100; System.out.println("tag a set number over"); Thread.sleep(1000); }else{ num1 = 200; System.out.println("tag b set number over"); } System.out.println("tag = "+ arg + ";num ="+ num1); } catch (InterruptedException e) { e.printStackTrace(); } } private static int num2; public static synchronized void method02(String arg) { try { if("a".equals(arg)){ num2 = 100; System.out.println("tag a set number over"); Thread.sleep(1000); }else{ num2 = 200; System.out.println("tag b set number over"); } System.out.println("tag = "+ arg + ";num ="+ num2); } catch (InterruptedException e) { e.printStackTrace(); } } } //調(diào)用method01方法打印日志【普通方法】 tag a set number over tag b set number over tag = b;num =200 tag = a;num =100 //調(diào)用method02方法打印日志【static靜態(tài)方法】 tag a set number over tag = a;num =100 tag b set number over tag = b;num =200
- 在static方法前加synchronized:靜態(tài)方法屬于類方法择克,它屬于這個(gè)類,獲取到的鎖前普,是屬于類的鎖肚邢。
- 在普通方法前加synchronized:非static方法獲取到的鎖,是屬于當(dāng)前對(duì)象的鎖拭卿。 技術(shù)博客大總結(jié)
- 結(jié)論:類鎖和對(duì)象鎖不同骡湖,synchronized修飾不加static的方法,鎖是加在單個(gè)對(duì)象上峻厚,不同的對(duì)象沒(méi)有競(jìng)爭(zhēng)關(guān)系响蕴;修飾加了static的方法,鎖是加載類上惠桃,這個(gè)類所有的對(duì)象競(jìng)爭(zhēng)一把鎖浦夷。
其他介紹
01.關(guān)于博客匯總鏈接
- 1.技術(shù)博客匯總
- 2.開(kāi)源項(xiàng)目匯總
- 3.生活博客匯總
- 4.喜馬拉雅音頻匯總
- 5.其他匯總
02.關(guān)于我的博客
- 我的個(gè)人站點(diǎn):www.yczbj.org,www.ycbjie.cn
- github:https://github.com/yangchong211
- 知乎:https://www.zhihu.com/people/yang-chong-69-24/pins/posts
- 簡(jiǎn)書(shū):http://www.reibang.com/u/b7b2c6ed9284
- csdn:http://my.csdn.net/m0_37700275
- 喜馬拉雅聽(tīng)書(shū):http://www.ximalaya.com/zhubo/71989305/
- 開(kāi)源中國(guó):https://my.oschina.net/zbj1618/blog
- 泡在網(wǎng)上的日子:http://www.jcodecraeer.com/member/content_list.php?channelid=1
- 郵箱:yangchong211@163.com
- 阿里云博客:https://yq.aliyun.com/users/article?spm=5176.100- 239.headeruserinfo.3.dT4bcV
- segmentfault頭條:https://segmentfault.com/u/xiangjianyu/articles
- 掘金:https://juejin.im/user/5939433efe88c2006afa0c6e