多線程

35. 并行和并發(fā)有什么區(qū)別?

并發(fā):多個(gè)任務(wù)在同一個(gè) CPU 核上,按細(xì)分的時(shí)間片輪流(交替)執(zhí)行,從邏輯上來(lái)看那些任務(wù)是同時(shí)執(zhí)行。

并行:多個(gè)處理器或多核處理器同時(shí)處理多個(gè)任務(wù)。

36. 線程和進(jìn)程的區(qū)別?

一個(gè)程序下至少有一個(gè)進(jìn)程,一個(gè)進(jìn)程下至少有一個(gè)線程,一個(gè)進(jìn)程下也可以有多個(gè)線程來(lái)增加程序的執(zhí)行速度。

37. 守護(hù)線程是什么?

守護(hù)線程是運(yùn)行在后臺(tái)的一種特殊進(jìn)程。它獨(dú)立于控制終端并且周期性地執(zhí)行某種任務(wù)或等待處理某些發(fā)生的事件。在 Java 中垃圾回收線程就是特殊的守護(hù)線程。

38. 創(chuàng)建線程有哪幾種方式?

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

繼承 Thread 重新 run 方法;

實(shí)現(xiàn) Runnable 接口;

實(shí)現(xiàn) Callable 接口。

39. 說(shuō)一下 runnable 和 callable 有什么區(qū)別?

runnable 沒(méi)有返回值,callable 可以拿到有返回值,callable 可以看作是 runnable 的補(bǔ)充。

40. 線程有哪些狀態(tài)?

線程的狀態(tài):

NEW 尚未啟動(dòng)

RUNNABLE 正在執(zhí)行中

BLOCKED 阻塞的(被同步鎖或者IO鎖阻塞)

WAITING 永久等待狀態(tài)

TIMED_WAITING 等待指定的時(shí)間重新被喚醒的狀態(tài)

TERMINATED 執(zhí)行完成

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

類的不同:sleep() 來(lái)自 Thread,wait() 來(lái)自 Object。

釋放鎖:sleep() 不釋放鎖;wait()

? ? 釋放鎖。

用法不同:sleep() 時(shí)間到會(huì)自動(dòng)恢復(fù);wait()

? ? 可以使用 notify()/notifyAll()直接喚醒。

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

線程獲取鎖,會(huì)執(zhí)行代碼。獲取不到的在鎖對(duì)象的等待池中。

鎖對(duì)象有兩個(gè)池子:等待池和鎖池

notifyAll() 調(diào)用后,會(huì)將全部線程由等待池移到鎖池,然后參與鎖的競(jìng)爭(zhēng),競(jìng)爭(zhēng)成功則繼續(xù)執(zhí)行,如果不成功則留在鎖池等待鎖被釋放后再次參與競(jìng)爭(zhēng)。而 notify()只會(huì)喚醒一個(gè)線程,具體喚醒哪一個(gè)線程由虛擬機(jī)控制。

43. 線程的 run() 和 start() 有什么區(qū)別?

start() 方法用于啟動(dòng)線程,run() 方法用于執(zhí)行線程的運(yùn)行時(shí)代碼。run() 可以重復(fù)調(diào)用,而 start() 只能調(diào)用一次。

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

線程池創(chuàng)建有七種方式,最核心的是最后一種:

newSingleThreadExecutor():它的特點(diǎn)在于工作線程數(shù)目被限制為 1,操作一個(gè)無(wú)界的工作隊(duì)列,所以它保證了所有任務(wù)的都是被順序執(zhí)行,最多會(huì)有一個(gè)任務(wù)處于活動(dòng)狀態(tài),并且不允許使用者改動(dòng)線程池實(shí)例,因此可以避免其改變線程數(shù)目;

newCachedThreadPool():它是一種用來(lái)處理大量短時(shí)間工作任務(wù)的線程池,具有幾個(gè)鮮明特點(diǎn):它會(huì)試圖緩存線程并重用,當(dāng)無(wú)緩存線程可用時(shí),就會(huì)創(chuàng)建新的工作線程;如果線程閑置的時(shí)間超過(guò) 60 秒,則被終止并移出緩存;長(zhǎng)時(shí)間閑置時(shí),這種線程池,不會(huì)消耗什么資源。其內(nèi)部使用 SynchronousQueue 作為工作隊(duì)列;

newFixedThreadPool(int nThreads):重用指定數(shù)目(nThreads)的線程,其背后使用的是無(wú)界的工作隊(duì)列,任何時(shí)候最多有 nThreads 個(gè)工作線程是活動(dòng)的。這意味著,如果任務(wù)數(shù)量超過(guò)了活動(dòng)隊(duì)列數(shù)目,將在工作隊(duì)列中等待空閑線程出現(xiàn);如果有工作線程退出,將會(huì)有新的工作線程被創(chuàng)建,以補(bǔ)足指定的數(shù)目 nThreads;

newSingleThreadScheduledExecutor():創(chuàng)建單線程池,返回? ? ScheduledExecutorService,可以進(jìn)行定時(shí)或周期性的工作調(diào)度;

newScheduledThreadPool(int corePoolSize):和newSingleThreadScheduledExecutor()類似,創(chuàng)建的是個(gè)? ? ScheduledExecutorService,可以進(jìn)行定時(shí)或周期性的工作調(diào)度,區(qū)別在于單一工作線程還是多個(gè)工作線程;

newWorkStealingPool(int parallelism):這是一個(gè)經(jīng)常被人忽略的線程池,Java 8 才加入這個(gè)創(chuàng)建方法,其內(nèi)部會(huì)構(gòu)建ForkJoinPool,利用Work-Stealing算法,并行地處理任務(wù),不保證處理順序;

ThreadPoolExecutor():是最原始的線程池創(chuàng)建,上面1-3創(chuàng)建方式都是對(duì)ThreadPoolExecutor的封裝。

45. 線程池都有哪些狀態(tài)?

RUNNING:這是最正常的狀態(tài),接受新的任務(wù),處理等待隊(duì)列中的任務(wù)。

SHUTDOWN:不接受新的任務(wù)提交,但是會(huì)繼續(xù)處理等待隊(duì)列中的任務(wù)。

STOP:不接受新的任務(wù)提交,不再處理等待隊(duì)列中的任務(wù),中斷正在執(zhí)行任務(wù)的線程。

TIDYING:所有的任務(wù)都銷毀了,workCount 為 0,線程池的狀態(tài)在轉(zhuǎn)換為 TIDYING 狀態(tài)時(shí),會(huì)執(zhí)行鉤子方法 terminated()。

TERMINATED:terminated()方法結(jié)束后,線程池的狀態(tài)就會(huì)變成這個(gè)。

46. 線程池中 submit() 和 execute() 方法有什么區(qū)別?

execute():只能執(zhí)行 Runnable 類型的任務(wù)。

submit():可以執(zhí)行 Runnable 和 Callable 類型的任務(wù)。

Callable 類型的任務(wù)可以獲取執(zhí)行的返回值,而 Runnable 執(zhí)行無(wú)返回值。

47. 在 Java 程序中怎么保證多線程的運(yùn)行安全?

方法一:使用安全類,比如 Java. util. concurrent 下的類。

方法二:使用自動(dòng)鎖 synchronized。

方法三:使用手動(dòng)鎖 Lock。

8. 多線程中 synchronized 鎖升級(jí)的原理是什么?

synchronized 鎖升級(jí)原理:在鎖對(duì)象的對(duì)象頭里面有一個(gè) threadid 字段,在第一次訪問(wèn)的時(shí)候 threadid 為空,jvm 讓其持有偏向鎖,并將 threadid 設(shè)置為其線程 id,再次進(jìn)入的時(shí)候會(huì)先判斷 threadid 是否與其線程 id 一致,如果一致則可以直接使用此對(duì)象,如果不一致,則升級(jí)偏向鎖為輕量級(jí)鎖,通過(guò)自旋循環(huán)一定次數(shù)來(lái)獲取鎖,執(zhí)行一定次數(shù)之后,如果還沒(méi)有正常獲取到要使用的對(duì)象,此時(shí)就會(huì)把鎖從輕量級(jí)升級(jí)為重量級(jí)鎖,此過(guò)程就構(gòu)成了 synchronized 鎖的升級(jí)。

鎖的升級(jí)的目的:鎖升級(jí)是為了減低了鎖帶來(lái)的性能消耗。在 Java 6 之后優(yōu)化 synchronized 的實(shí)現(xiàn)方式,使用了偏向鎖升級(jí)為輕量級(jí)鎖再升級(jí)到重量級(jí)鎖的方式,從而減低了鎖帶來(lái)的性能消耗。

9. 什么是死鎖?

當(dāng)線程 A 持有獨(dú)占鎖a,并嘗試去獲取獨(dú)占鎖 b 的同時(shí),線程 B 持有獨(dú)占鎖 b,并嘗試獲取獨(dú)占鎖 a 的情況下,就會(huì)發(fā)生 AB 兩個(gè)線程由于互相持有對(duì)方需要的鎖,而發(fā)生的阻塞現(xiàn)象,我們稱為死鎖。

1. ThreadLocal 是什么?有哪些使用場(chǎng)景?

ThreadLocal 為每個(gè)使用該變量的線程提供獨(dú)立的變量副本,所以每一個(gè)線程都可以獨(dú)立地改變自己的副本,而不會(huì)影響其它線程所對(duì)應(yīng)的副本。

ThreadLocal 的經(jīng)典使用場(chǎng)景是數(shù)據(jù)庫(kù)連接和 session 管理等。

52. 說(shuō)一下 synchronized 底層實(shí)現(xiàn)原理?

synchronized 是由一對(duì) monitorenter/monitorexit 指令實(shí)現(xiàn)的,monitor 對(duì)象是同步的基本實(shí)現(xiàn)單元。在 Java 6 之前,monitor 的實(shí)現(xiàn)完全是依靠操作系統(tǒng)內(nèi)部的互斥鎖,因?yàn)樾枰M(jìn)行用戶態(tài)到內(nèi)核態(tài)的切換,所以同步操作是一個(gè)無(wú)差別的重量級(jí)操作,性能也很低。但在 Java 6 的時(shí)候,Java 虛擬機(jī) 對(duì)此進(jìn)行了大刀闊斧地改進(jìn),提供了三種不同的 monitor 實(shí)現(xiàn),也就是常說(shuō)的三種不同的鎖:偏向鎖(Biased Locking)、輕量級(jí)鎖和重量級(jí)鎖,大大改進(jìn)了其性能。

53. synchronized 和 volatile 的區(qū)別是什么?

volatile 是變量修飾符;synchronized 是修飾類、方法、代碼段。

volatile 僅能實(shí)現(xiàn)變量的修改可見(jiàn)性,不能保證原子性;而 synchronized 則可以保證變量的修改可見(jiàn)性和原子性。

volatile 不會(huì)造成線程的阻塞;synchronized 可能會(huì)造成線程的阻塞。

54. synchronized 和 Lock 有什么區(qū)別?

synchronized 可以給類、方法、代碼塊加鎖;而 lock 只能給代碼塊加鎖。

synchronized 不需要手動(dòng)獲取鎖和釋放鎖,使用簡(jiǎn)單,發(fā)生異常會(huì)自動(dòng)釋放鎖,不會(huì)造成死鎖;而 lock 需要自己加鎖和釋放鎖,如果使用不當(dāng)沒(méi)有 unLock()去釋放鎖就會(huì)造成死鎖。

通過(guò) Lock 可以知道有沒(méi)有成功獲取鎖,而 synchronized 卻無(wú)法辦到。

55. synchronized 和 ReentrantLock 區(qū)別是什么?

synchronized 早期的實(shí)現(xiàn)比較低效,對(duì)比 ReentrantLock,大多數(shù)場(chǎng)景性能都相差較大,但是在 Java 6 中對(duì) synchronized 進(jìn)行了非常多的改進(jìn)。

主要區(qū)別如下:

ReentrantLock 使用起來(lái)比較靈活,但是必須有釋放鎖的配合動(dòng)作;

ReentrantLock 必須手動(dòng)獲取與釋放鎖,而 synchronized 不需要手動(dòng)釋放和開(kāi)啟鎖;

ReentrantLock 只適用于代碼塊鎖,而 synchronized 可用于修飾方法、代碼塊等。

volatile 標(biāo)記的變量不會(huì)被編譯器優(yōu)化;synchronized 標(biāo)記的變量可以被編譯器優(yōu)化。

56. 說(shuō)一下 atomic 的原理?

atomic 主要利用 CAS (Compare And Wwap) 和 volatile 和 native 方法來(lái)保證原子操作,從而避免 synchronized 的高開(kāi)銷,執(zhí)行效率大為提升。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • ??一個(gè)任務(wù)通常就是一個(gè)程序,每個(gè)運(yùn)行中的程序就是一個(gè)進(jìn)程。當(dāng)一個(gè)程序運(yùn)行時(shí),內(nèi)部可能包含了多個(gè)順序執(zhí)行流,每個(gè)順...
    OmaiMoon閱讀 1,804評(píng)論 0 12
  • Java-Review-Note——4.多線程 標(biāo)簽: JavaStudy PS:本來(lái)是分開(kāi)三篇的,后來(lái)想想還是整...
    coder_pig閱讀 1,772評(píng)論 2 17
  • 下面最近發(fā)的一些并發(fā)編程的文章匯總,通過(guò)閱讀這些文章大家再看大廠面試中的并發(fā)編程問(wèn)題就沒(méi)有那么頭疼了。今天給大家總...
    架構(gòu)師springboot閱讀 801評(píng)論 0 3
  • 先看幾個(gè)概念:線程:進(jìn)程中負(fù)責(zé)程序執(zhí)行的執(zhí)行單元。一個(gè)進(jìn)程中至少有一個(gè)線程。多線程:解決多任務(wù)同時(shí)執(zhí)行的需求,合理...
    yeying12321閱讀 614評(píng)論 0 0
  • 線程池ThreadPoolExecutor corepoolsize:核心池的大小,默認(rèn)情況下,在創(chuàng)建了線程池之后...
    irckwk1閱讀 864評(píng)論 0 0

友情鏈接更多精彩內(nèi)容