05.java多線程問(wèn)題

目錄介紹

  • 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ì)降低程序的性能磅甩,那么該如何做才能降低性能炊林?

  • 線程池好處:
  • 線程池的實(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)入
  • 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ū)別

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)用的
  • 同步方法和同步塊,哪個(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)于博客匯總鏈接

02.關(guān)于我的博客

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末辜王,一起剝皮案震驚了整個(gè)濱河市劈狐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌誓禁,老刑警劉巖懈息,帶你破解...
    沈念sama閱讀 222,729評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肾档,死亡現(xiàn)場(chǎng)離奇詭異摹恰,居然都是意外死亡辫继,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)俗慈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)姑宽,“玉大人,你說(shuō)我怎么就攤上這事闺阱∨诔担” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,461評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵酣溃,是天一觀的道長(zhǎng)瘦穆。 經(jīng)常有香客問(wèn)我,道長(zhǎng)赊豌,這世上最難降的妖魔是什么扛或? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,135評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮碘饼,結(jié)果婚禮上熙兔,老公的妹妹穿的比我還像新娘。我一直安慰自己艾恼,他們只是感情好住涉,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著钠绍,像睡著了一般舆声。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上柳爽,一...
    開(kāi)封第一講書(shū)人閱讀 52,736評(píng)論 1 312
  • 那天纳寂,我揣著相機(jī)與錄音,去河邊找鬼泻拦。 笑死毙芜,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的争拐。 我是一名探鬼主播腋粥,決...
    沈念sama閱讀 41,179評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼架曹!你這毒婦竟也來(lái)了隘冲?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 40,124評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤绑雄,失蹤者是張志新(化名)和其女友劉穎展辞,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體万牺,經(jīng)...
    沈念sama閱讀 46,657評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡罗珍,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評(píng)論 3 342
  • 正文 我和宋清朗相戀三年洽腺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片覆旱。...
    茶點(diǎn)故事閱讀 40,872評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蘸朋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出扣唱,到底是詐尸還是另有隱情藕坯,我是刑警寧澤,帶...
    沈念sama閱讀 36,533評(píng)論 5 351
  • 正文 年R本政府宣布噪沙,位于F島的核電站炼彪,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏正歼。R本人自食惡果不足惜霹购,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望朋腋。 院中可真熱鬧齐疙,春花似錦、人聲如沸旭咽。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,700評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)穷绵。三九已至轿塔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間仲墨,已是汗流浹背勾缭。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,819評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留目养,地道東北人俩由。 一個(gè)月前我還...
    沈念sama閱讀 49,304評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像癌蚁,于是被迫代替她去往敵國(guó)和親幻梯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評(píng)論 2 361

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

  • 本文首發(fā)于我的個(gè)人博客:尾尾部落 本文是我刷了幾十篇一線互聯(lián)網(wǎng)校招java后端開(kāi)發(fā)崗位的面經(jīng)后總結(jié)的多線程相關(guān)題目...
    繁著閱讀 2,012評(píng)論 0 7
  • 進(jìn)程和線程 進(jìn)程 所有運(yùn)行中的任務(wù)通常對(duì)應(yīng)一個(gè)進(jìn)程,當(dāng)一個(gè)程序進(jìn)入內(nèi)存運(yùn)行時(shí),即變成一個(gè)進(jìn)程.進(jìn)程是處于運(yùn)行過(guò)程中...
    勝浩_ae28閱讀 5,120評(píng)論 0 23
  • 從三月份找實(shí)習(xí)到現(xiàn)在努释,面了一些公司碘梢,掛了不少,但最終還是拿到小米伐蒂、百度煞躬、阿里、京東、新浪恩沛、CVTE在扰、樂(lè)視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,280評(píng)論 11 349
  • Java-Review-Note——4.多線程 標(biāo)簽: JavaStudy PS:本來(lái)是分開(kāi)三篇的,后來(lái)想想還是整...
    coder_pig閱讀 1,655評(píng)論 2 17
  • Java多線程學(xué)習(xí) [-] 一擴(kuò)展javalangThread類 二實(shí)現(xiàn)javalangRunnable接口 三T...
    影馳閱讀 2,966評(píng)論 1 18