Java并發(fā)面試題

創(chuàng)建線程的三種方式

1.繼承Thread類創(chuàng)建線程
2.實(shí)現(xiàn)Runnable接口創(chuàng)建線程
3.使用Callable和Future創(chuàng)建線程(和Runnable接口不一樣牢屋,Callable接口提供了一個(gè)call()方法作為線程執(zhí)行體耸黑,call()方法比run()方法功能要強(qiáng)大。)

線程的狀態(tài)

1.新建狀態(tài)(New) :線程對(duì)象被創(chuàng)建后,就進(jìn)入了新建狀態(tài)。例如毙籽,Thread thread = new
Thread()。
2.就緒狀態(tài)(Runnable): 也被稱為“可執(zhí)行狀態(tài)”虫啥。線程對(duì)象被創(chuàng)建后蔚约,其它線程調(diào)用了該對(duì)象的start()方法,從而來啟動(dòng)該線程涂籽。例如苹祟,thread.start()。處于就緒狀態(tài)的線程评雌,隨時(shí)可能被CPU調(diào)度執(zhí)行树枫。
3.運(yùn)行狀態(tài)(Running) : 線程獲取CPU權(quán)限進(jìn)行執(zhí)行。需要注意的是景东,線程只能從就緒狀態(tài)進(jìn)入到運(yùn)行狀態(tài)砂轻。
4.阻塞狀態(tài)(Blocked) :阻塞狀態(tài)是線程因?yàn)槟撤N原因放棄CPU使用權(quán),暫時(shí)停止運(yùn)行斤吐。直到線程進(jìn)入就緒狀態(tài)搔涝,才有機(jī)會(huì)轉(zhuǎn)到運(yùn)行狀態(tài)。阻塞的情況分三種: (01)等待阻塞 -- 通過調(diào)用線程的wait()方法和措,讓線程等待某工作的完成庄呈。 (02)同步阻塞 -- 線程在獲取synchronized同步鎖失敗(因?yàn)殒i被其它線程所占用),它會(huì)進(jìn)入同步阻塞狀態(tài)派阱。 (03)其他阻塞 -- 通過調(diào)用線程的sleep()或join()或發(fā)出了I/O請(qǐng)求時(shí)诬留,線程會(huì)進(jìn)入到阻塞狀態(tài)。當(dāng)sleep()狀態(tài)超時(shí)、join()等待線程終止或者超時(shí)文兑、或者I/O處理完畢時(shí)盒刚,線程重新轉(zhuǎn)入就緒狀態(tài)。
5.死亡狀態(tài)(Dead) :線程執(zhí)行完了或者因異常退出了run()方法彩届,該線程結(jié)束生命周期伪冰。

sleep()和 wait() 有什么區(qū)別?

1.wait()方法屬于Object類,sleep()屬于Thread類樟蠕;
2.wait()方法釋放cpu給其他線程贮聂,自己讓出資源進(jìn)入等待池等待;sleep占用cpu寨辩,不讓出資源吓懈;
3.sleep()必須指定時(shí)間,wait()可以指定時(shí)間也可以不指定靡狞;sleep()時(shí)間到耻警,線程處于臨時(shí)阻塞或運(yùn)行狀態(tài);
4.wait()方法會(huì)釋放持有的鎖甸怕,不然其他線程不能進(jìn)入同步方法或同步塊甘穿,從而不能調(diào)用notify(),notifyAll()方法來喚醒線程,產(chǎn)生死鎖梢杭,所以釋放鎖温兼,可以執(zhí)行其他線程,也可以喚醒自己武契,只是設(shè)置停止自己的時(shí)間時(shí)不確定的募判;sleep方法不會(huì)釋放持有的鎖,設(shè)置sleep的時(shí)間是確定的會(huì)按時(shí)執(zhí)行的咒唆;
5.wait()
方法只能在同步方法或同步代碼塊中調(diào)用届垫,否則會(huì)報(bào)illegalMonitorStateException異常,如果沒有設(shè)定時(shí)間全释,使用notify()來喚醒装处;而sleep()能在任何地方調(diào)用;

Thread類的 sleep()方法和對(duì)象的wait()方法都可以讓線程暫停執(zhí)行恨溜,它們有什么區(qū)別?

sleep()方法(休眠)是線程類(Thread)的靜態(tài)方法符衔,調(diào)用此方法會(huì)讓當(dāng)前線程暫停執(zhí)行指定的時(shí)間,將執(zhí)行機(jī)會(huì)(CPU)讓給其他線程糟袁,但是對(duì)象的鎖依然保持判族,因此休眠時(shí)間結(jié)束后會(huì)自動(dòng)恢復(fù)(線程回到就緒狀態(tài),請(qǐng)參考第 66 題中的線程狀態(tài)轉(zhuǎn)換圖)项戴。wait()是 Object 類的方法形帮,調(diào)用對(duì)象的 wait()方法導(dǎo)致當(dāng)前線程放棄對(duì)象的鎖(線程暫停執(zhí)行),進(jìn)入對(duì)象的等待池(wait pool),只有調(diào)用對(duì)象的 notify()方法(或 notifyAll()方法)時(shí)才能喚醒等待池中的線程進(jìn)入等鎖池(lock pool)辩撑,如果線程重新獲得對(duì)象的鎖就可以進(jìn)入就緒狀態(tài)界斜。補(bǔ)充:可能不少人對(duì)什么是進(jìn)程,什么是線程還比較模糊合冀,對(duì)于為什么需要多線程編程也不是特別理解各薇。簡單的說:進(jìn)程是具有一定獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)集合上的一次運(yùn)行活動(dòng),是操作系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位君躺;線程是進(jìn)程的一個(gè)實(shí)體峭判,是 CPU 調(diào)度和分派的基本單位,是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位棕叫。線程的劃分尺度小于進(jìn)程林螃,這使得多線程程序的并發(fā)性高;進(jìn)程在執(zhí)行時(shí)通常擁有獨(dú)立的內(nèi)存單元俺泣,而線程之間可以共享內(nèi)存疗认。使用多線程的編程通常能夠帶來更好的性能和用戶體驗(yàn),但是多線程的程序?qū)τ谄渌绦蚴遣挥押玫姆疲驗(yàn)樗赡苷加昧烁嗟?CPU 資源横漏。當(dāng)然,也不是線程越多熟掂,程序的性能就越好绊茧,因?yàn)榫€程之間的調(diào)度和切換也會(huì)浪費(fèi)CPU 時(shí)間。時(shí)下很時(shí)髦的 Node.js就采用了單線程異步I/O 的工作模式打掘。

請(qǐng)說出與線程同步以及線程調(diào)度相關(guān)的方法。

(1) wait():使一個(gè)線程處于等待(阻塞)狀態(tài)鹏秋,并且釋放所持有的對(duì)象的鎖尊蚁;
(2)sleep():使一個(gè)正在運(yùn)行的線程處于睡眠狀態(tài),是一個(gè)靜態(tài)方法侣夷,調(diào)用此方法要處理 InterruptedException 異常横朋;
(3)notify():喚醒一個(gè)處于等待狀態(tài)的線程,當(dāng)然在調(diào)用此方法的時(shí)候百拓,并不能確切的喚醒某一個(gè)等待狀態(tài)的線程琴锭,而是由 JVM 確定喚醒哪個(gè)線程,而且與優(yōu)先級(jí)無關(guān)衙传;
(4)notityAll():喚醒所有處于等待狀態(tài)的線程决帖,該方法并不是將對(duì)象的鎖給所有線程,而是讓它們競(jìng)爭蓖捶,只有獲得鎖的線程才能進(jìn)入就緒狀態(tài)地回;

補(bǔ)充:Java 5 通過 Lock 接口提供了顯式的鎖機(jī)制(explicit lock),增強(qiáng)了靈活性以及對(duì)線程的協(xié)調(diào)。Lock 接口中定義了加鎖(lock())和解鎖(unlock())的方法刻像,同時(shí)還提供了 newCondition()方法來產(chǎn)生用于線程之間通信的 Condition 對(duì)象畅买;此外,Java 5 還提供了信號(hào)量機(jī)制(semaphore)细睡,信號(hào)量可以用來限制對(duì)某個(gè)共享資源進(jìn)行訪問的線程的數(shù)量谷羞。在對(duì)資源進(jìn)行訪問之前,線程必須得到信號(hào)量的許可(調(diào)用 Semaphore 對(duì)象的 acquire()方法)溜徙;在完成對(duì)資源的訪問后湃缎,線程必須向信號(hào)量歸還許可(調(diào)用 Semaphore 對(duì)象的 release()方法)。

簡述 synchronized 和 java.util.concurrent.locks.Lock的異同萌京?

Lock是 Java 5 以后引入的新的 API雁歌,和關(guān)鍵字 synchronized 相比主要相同點(diǎn):Lock 能完成 synchronized 所實(shí)現(xiàn)的所有功能;主要不同點(diǎn):Lock 有比synchronized 更精確的線程語義和更好的性能知残,而且不強(qiáng)制性的要求一定要獲得鎖靠瞎。synchronized會(huì)自動(dòng)釋放鎖,而 Lock 一定要求程序員手工釋放求妹,并且最好在finally 塊中釋放(這是釋放外部資源的最好的地方)乏盐。

notify()和 notifyAll()有什么區(qū)別?

Java中notify和notifyAll的區(qū)別:
Java提供了兩個(gè)方法notify和notifyAll來喚醒在某些條件下等待的線程制恍,你可以使用它們中的任何一個(gè)父能,但是Java中的notify和notifyAll之間存在細(xì)微差別,這使得它成為Java中流行的多線程面試問題之一净神。當(dāng)你調(diào)用notify時(shí)何吝,只有一個(gè)等待線程會(huì)被喚醒而且它不能保證哪個(gè)線程會(huì)被喚醒,這取決于線程調(diào)度器鹃唯。雖然如果你調(diào)用notifyAll方法涤垫,那么等待該鎖的所有線程都會(huì)被喚醒苞七,但是在執(zhí)行剩余的代碼之前,所有被喚醒的線程都將爭奪鎖定,這就是為什么在循環(huán)上調(diào)用wait驻右,因?yàn)槿绻鄠€(gè)線程被喚醒驰贷,那么線程是將獲得鎖定將首先執(zhí)行颠区,它可能會(huì)重置等待條件荠割,這將迫使后續(xù)線程等待。因此熄求,notify和notifyAll之間的關(guān)鍵區(qū)別在于notify()只會(huì)喚醒一個(gè)線程渣玲,而notifyAll方法將喚醒所有線程。

創(chuàng)建線程池有哪幾種方式弟晚?

Java通過Executors提供四種線程池柜蜈,分別為:
newCachedThreadPool創(chuàng)建一個(gè)可緩存線程池仗谆,如果線程池長度超過處理需要,可靈活回收空閑線程淑履,若無可回收隶垮,則新建線程。
newFixedThreadPool創(chuàng)建一個(gè)定長線程池秘噪,可控制線程最大并發(fā)數(shù)狸吞,超出的線程會(huì)在隊(duì)列中等待。
newScheduledThreadPool創(chuàng)建一個(gè)定長線程池指煎,支持定時(shí)及周期性任務(wù)執(zhí)行蹋偏。
newSingleThreadExecutor創(chuàng)建一個(gè)單線程化的線程池,它只會(huì)用唯一的工作線程來執(zhí)行任務(wù)至壤,保證所有任務(wù)按照指定順序(FIFO, LIFO, 優(yōu)先級(jí))執(zhí)行威始。

在 Java 中 Executor 和 Executors 的區(qū)別?

Executors工具類的不同方法按照我們的需求創(chuàng)建了不同的線程池像街,來滿足業(yè)務(wù)的需求黎棠。
Executor接口對(duì)象能執(zhí)行我們的線程任務(wù)。
ExecutorService接口繼承了 Executor 接口并進(jìn)行了擴(kuò)展镰绎,提供了更多的方法我們能獲得任務(wù)執(zhí)行的狀態(tài)并且可以獲取任務(wù)的返回值脓斩。使用 ThreadPoolExecutor 可以創(chuàng)建自定義線程池。
Future表示異步計(jì)算的結(jié)果畴栖,他提供了檢查計(jì)算是否完成的方法随静,以等待計(jì)算的完成,并可以使用 get()方法獲取計(jì)算的結(jié)果吗讶。

java如何實(shí)現(xiàn)多線程之間的通訊和協(xié)作燎猛?

中斷和共享變量

什么是可重入鎖(ReentrantLock)?

如何實(shí)現(xiàn)阻塞隊(duì)列

如何確保線程安全照皆?

在 Java 中可以有很多方法來保證線程安全——同步扛门,使用原子類(atomic concurrent classes),實(shí)現(xiàn)并發(fā)鎖纵寝,使用volatile 關(guān)鍵字,使用不變類和線程安全類星立。

Java 中15種鎖

公平鎖 / 非公平鎖
可重入鎖 / 不可重入鎖
獨(dú)享鎖 / 共享鎖
互斥鎖 / 讀寫鎖
樂觀鎖 / 悲觀鎖
分段鎖
偏向鎖 / 輕量級(jí)鎖 / 重量級(jí)鎖
自旋鎖

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末爽茴,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子绰垂,更是在濱河造成了極大的恐慌室奏,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件劲装,死亡現(xiàn)場(chǎng)離奇詭異胧沫,居然都是意外死亡昌简,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門绒怨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纯赎,“玉大人,你說我怎么就攤上這事南蹂∪穑” “怎么了?”我有些...
    開封第一講書人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵六剥,是天一觀的道長晚顷。 經(jīng)常有香客問我,道長疗疟,這世上最難降的妖魔是什么该默? 我笑而不...
    開封第一講書人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮策彤,結(jié)果婚禮上栓袖,老公的妹妹穿的比我還像新娘。我一直安慰自己锅锨,他們只是感情好叽赊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著必搞,像睡著了一般必指。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上恕洲,一...
    開封第一講書人閱讀 51,698評(píng)論 1 305
  • 那天塔橡,我揣著相機(jī)與錄音,去河邊找鬼霜第。 笑死葛家,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的泌类。 我是一名探鬼主播癞谒,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼刃榨!你這毒婦竟也來了弹砚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤枢希,失蹤者是張志新(化名)和其女友劉穎桌吃,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體苞轿,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡茅诱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年逗物,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瑟俭。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡翎卓,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出尔当,到底是詐尸還是另有隱情莲祸,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布椭迎,位于F島的核電站锐帜,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏畜号。R本人自食惡果不足惜缴阎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望简软。 院中可真熱鬧蛮拔,春花似錦、人聲如沸痹升。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽疼蛾。三九已至肛跌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間察郁,已是汗流浹背衍慎。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留皮钠,地道東北人稳捆。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像麦轰,于是被迫代替她去往敵國和親乔夯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355