溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

java多線程的核心知識(shí)點(diǎn)是什么

發(fā)布時(shí)間:2021-07-15 09:20:32 來(lái)源:億速云 閱讀:159 作者:chen 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要介紹“java多線程的核心知識(shí)點(diǎn)是什么”,在日常操作中,相信很多人在java多線程的核心知識(shí)點(diǎn)是什么問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”java多線程的核心知識(shí)點(diǎn)是什么”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

目錄
  • 一、鎖的概念

  • 二、synchronized 的使用方式

  • 三、synchronized 的實(shí)現(xiàn)原理列

    • 小結(jié)

  • 四、線程池是什么

    • 五、為什么要用線程池?

      • 六、看下類圖,從整體上理解下

        • 七、線程池的創(chuàng)建

          • 八、線程池核心參數(shù)說(shuō)明

            • 九、幾個(gè)疑問(wèn)點(diǎn)

              • 9.1、是怎么保證線程不銷毀的?

              • 9.2 提交任務(wù)有哪幾種方式?

              • 9.3 拒絕策略都有哪些?

              • 9.4 線程池的關(guān)閉

              • 9.5 初始化線程池時(shí)線程數(shù)的選擇

            • 十、總結(jié)

              一、鎖的概念

              先來(lái)聊聊這幾個(gè)概念,總不能聊起來(lái)的時(shí)候啥也不知道,只知道干活也沒(méi)有用。

              公平鎖:當(dāng)線程A獲取訪問(wèn)該對(duì)象,獲取到鎖后,此時(shí)內(nèi)部存在一個(gè)計(jì)數(shù)器num+1,其他線程想訪問(wèn)該對(duì)象,就會(huì)進(jìn)行排隊(duì)等待(等待隊(duì)列最前一個(gè)線程處于待喚醒狀態(tài)),直到線程A釋放鎖(num = 0),此時(shí)會(huì)喚醒處于待喚醒狀態(tài)的線程進(jìn)行獲取鎖的操作,一直循環(huán)。如果線程A再次嘗試獲取該對(duì)象鎖時(shí),會(huì)檢查該對(duì)象鎖釋放已經(jīng)被占用,如果還是當(dāng)前線程占用鎖,則直接獲得鎖,不用進(jìn)入排隊(duì)。

              非公平鎖:當(dāng)線程A在釋放鎖后,等待對(duì)象的線程會(huì)進(jìn)行資源競(jìng)爭(zhēng),競(jìng)爭(zhēng)成功的線程將獲取該鎖,其他線程繼續(xù)睡眠。

              公平鎖是嚴(yán)格的以FIFO的方式進(jìn)行鎖的競(jìng)爭(zhēng),但是非公平鎖是無(wú)序的鎖競(jìng)爭(zhēng),剛釋放鎖的線程很大程度上能比較快的獲取到鎖,隊(duì)列中的線程只能等待,所以非公平鎖可能會(huì)有“饑餓”的問(wèn)題。但是重復(fù)的鎖獲取能減小線程之間的切換,而公平鎖則是嚴(yán)格的線程切換,這樣對(duì)操作系統(tǒng)的影響是比較大的,所以非公平鎖的吞吐量是大于公平鎖的,這也是為什么JDK將非公平鎖作為默認(rèn)的實(shí)現(xiàn)。

              悲觀鎖:總是假設(shè)最壞的情況,每次想要使用數(shù)據(jù)的時(shí)候就恰好別人也要修改數(shù)據(jù),一切是以安全第一,所以在每次操作資源的時(shí)候都會(huì)先加鎖,不管有沒(méi)有人搶,然后獨(dú)占資源。Java中synchronized和ReentrantLock等獨(dú)占鎖就是悲觀鎖思想的實(shí)現(xiàn)

              樂(lè)觀鎖:樂(lè)觀鎖和悲觀鎖剛好相反,假定自己使用資源的時(shí)候沒(méi)有人搶,所以不需要上鎖。樂(lè)觀鎖的實(shí)現(xiàn)方案一般來(lái)說(shuō)有兩種:版本號(hào)機(jī)制 和 CAS實(shí)現(xiàn) 。下期可能會(huì)講。

              在Java中java.util.concurrent.atomic包下面的原子變量類就是使用了樂(lè)觀鎖的一種實(shí)現(xiàn)方式CAS實(shí)現(xiàn)的。

              二、synchronized 的使用方式

              場(chǎng)景具體分類鎖對(duì)象代碼示例
              修飾方法實(shí)例方法當(dāng)前實(shí)例對(duì)象public synchronized void method () { ... }
              ...靜態(tài)方法當(dāng)前類的Class對(duì)象public static synchronized void method () { ... }
              修飾代碼塊代碼塊( )中配置的對(duì)象synchronized(object) { ... }

              三、synchronized 的實(shí)現(xiàn)原理列

              想知道原來(lái)先去底層看下,看看字節(jié)碼是什么樣子的,let's go!

                private static Object lock = new Object();
                public static synchronized void testSyn() {
                    System.out.println("香菜");
                }
                public synchronized void testSyn2() {
                    System.out.println("香菜");
                }
                public static void testObj() {
                    synchronized (lock) {
                        System.out.println("香菜");
                    }
                }

              看下字節(jié)碼:

              java多線程的核心知識(shí)點(diǎn)是什么

              可以看到synchronized 的地方使用的是monitorenter指令,每個(gè)對(duì)象都和一個(gè)monitor對(duì)象關(guān)聯(lián),主要用來(lái)控制互斥資源的訪問(wèn),如果你想要加鎖必須先獲得monitor的批準(zhǔn),如果現(xiàn)在正有線程訪問(wèn),會(huì)把申請(qǐng)的線程加入到等待隊(duì)列。

              小結(jié)

              1、 無(wú)論synchronized關(guān)鍵字加在方法上還是對(duì)象上,如果它作用的對(duì)象是非靜態(tài)的,則它取得的鎖是對(duì)象;如果synchronized作用的對(duì)象是一個(gè)靜態(tài)方法或一個(gè)類,則它取得的鎖是對(duì)class對(duì)象的鎖,該類所有的對(duì)象同一把鎖。2、每個(gè)對(duì)象只有一個(gè)鎖(lock)與之相關(guān)聯(lián),誰(shuí)拿到這個(gè)鎖誰(shuí)就可以運(yùn)行它所控制的那段代碼。

              3、實(shí)現(xiàn)同步是要很大的系統(tǒng)開(kāi)銷作為代價(jià)的,甚至可能造成死鎖,所以盡量避免無(wú)謂的同步控制,避免做嵌套synchronized 的使用。

              4、synchronized 要盡量控制范圍,不能范圍太大,否則會(huì)損失系統(tǒng)性能。

              四、線程池是什么

              線程池就是一個(gè)對(duì)象持有一堆線程,舉個(gè)例子就是餓了么養(yǎng)的騎手團(tuán)隊(duì)。線程池就是這個(gè)團(tuán)隊(duì),每個(gè)騎手都是一個(gè)線程。

              五、為什么要用線程池?

              假如現(xiàn)在商家有外賣單子,需要騎手去送單,這個(gè)時(shí)候的外賣任務(wù)就會(huì)派單給騎手,為什么要用線程池吶?

              有幾個(gè)好處,第一就是騎手的招聘是有成本的,等你有了外賣訂單再去招聘,來(lái)不及了,不如平常養(yǎng)一些騎手,線程的創(chuàng)建和銷毀的開(kāi)銷是巨大的。

              第二就是不能一個(gè)單子來(lái)了就來(lái)一個(gè)騎手,這樣的話騎手的數(shù)量很難控制,對(duì)于派單來(lái)說(shuō)也存在很大的壓力,會(huì)造成整個(gè)騎手團(tuán)隊(duì)的崩潰,對(duì)應(yīng)的就是可以通過(guò)線程池控制系統(tǒng)內(nèi)的線程數(shù)量,有效的避免大量的線程池爭(zhēng)奪CPU資源而造成堵塞。

              第三如果養(yǎng)了一個(gè)騎手團(tuán)隊(duì),這樣在騎手的管理上可以規(guī)范,以便提供更好的外賣服務(wù),比如這種外賣超時(shí),騎手打星等。對(duì)比線程池就是線程池可以提供定時(shí)、定期、單線程、并發(fā)數(shù)控制等功能。

              六、看下類圖,從整體上理解下

              java多線程的核心知識(shí)點(diǎn)是什么

              七、線程池的創(chuàng)建

              java多線程的核心知識(shí)點(diǎn)是什么

              線程池主要使用的四種

              固定數(shù)量的線程池(FixedThreadPool

              定時(shí)線程池(ScheduledThreadPool

              可緩存線程池(CachedThreadPool

              單線程化線程池(SingleThreadExecutor

              八、線程池核心參數(shù)說(shuō)明

              首先看下如何構(gòu)造一個(gè)線程池

                public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
                    return new ThreadPoolExecutor(nThreads, nThreads,
                                                  0L, TimeUnit.MILLISECONDS,
                                                  new LinkedBlockingQueue<Runnable>(),
                                                  threadFactory);
                    public ThreadPoolExecutor(int corePoolSize,
                                          int maximumPoolSize,
                                          long keepAliveTime,
                                          TimeUnit unit,
                                          BlockingQueue<Runnable> workQueue,
                                          ThreadFactory threadFactory,
                                          RejectedExecutionHandler handler)

              核心參數(shù)說(shuō)明:

              java多線程的核心知識(shí)點(diǎn)是什么

              九、幾個(gè)疑問(wèn)點(diǎn)

              9.1、是怎么保證線程不銷毀的?

              核心線程會(huì)阻塞等待workQueue

              9.2 提交任務(wù)有哪幾種方式?

              java多線程的核心知識(shí)點(diǎn)是什么

              9.3 拒絕策略都有哪些?

              拒絕策略(handler)當(dāng)線程池的線程數(shù)達(dá)到最大線程數(shù)時(shí),需要執(zhí)行拒絕策略。拒絕策略需要實(shí)現(xiàn)RejectedExecutionHandler接口,并實(shí)現(xiàn)rejectedExecution(Runnable r, ThreadPoolExecutor executor)方法。不過(guò)Executors框架已經(jīng)為我們實(shí)現(xiàn)了4種拒絕策略:

              AbortPolicy(默認(rèn)):丟棄任務(wù)并拋出RejectedExecutionException異常。

              CallerRunsPolicy:由調(diào)用線程處理該任務(wù)。

              DiscardPolicy:丟棄任務(wù),但是不拋出異常??梢耘浜线@種模式進(jìn)行自定義的處理方式。

              DiscardOldestPolicy:丟棄隊(duì)列最早的未處理任務(wù),然后重新嘗試執(zhí)行任務(wù)。

              9.4 線程池的關(guān)閉

              關(guān)閉線程池可以調(diào)用shutdownNow和shutdown兩個(gè)方法來(lái)實(shí)現(xiàn)

              shutdownNow:對(duì)正在執(zhí)行的任務(wù)全部發(fā)出interrupt(),停止執(zhí)行,對(duì)還未開(kāi)始執(zhí)行的任務(wù)全部取消,并且返回還沒(méi)開(kāi)始的任務(wù)列表。

              shutdown:當(dāng)我們調(diào)用shutdown后,線程池將不再接受新的任務(wù),但也不會(huì)去強(qiáng)制終止已經(jīng)提交或者正在執(zhí)行中的任務(wù)。

              9.5 初始化線程池時(shí)線程數(shù)的選擇

              如果任務(wù)是IO密集型,一般線程數(shù)需要設(shè)置2倍CPU數(shù)以上,以此來(lái)盡量利用CPU資源。

              如果任務(wù)是CPU密集型,一般線程數(shù)量只需要設(shè)置CPU數(shù)加1即可,更多的線程數(shù)也只能增加上下文切換,不能增加CPU利用率。

              具體問(wèn)題具體分析。

              十、總結(jié)

              線程池是項(xiàng)目中常用的,需要理解線程池的應(yīng)用場(chǎng)景和構(gòu)造函數(shù),正確的使用線程池。

              到此,關(guān)于“java多線程的核心知識(shí)點(diǎn)是什么”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

              向AI問(wèn)一下細(xì)節(jié)

              免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

              AI