91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

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

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

05.java多線程問題

發布時間:2020-06-16 23:03:10 來源:網絡 閱讀:263 作者:楊充 欄目:移動開發

目錄介紹

  • 5.0.0.1 線程池具有什么優點和缺點?為什么說開啟大量的線程,會降低程序的性能,那么該如何做才能降低性能?
  • 5.0.0.3 線程中start和run方法有什么區別?wait和sleep方法的不同?sleep() 、join()、yield()有什么區別?
  • 5.0.0.4 用Java手寫一個會導致死鎖的程序,遇到這種問題解決方案是什么?那些場景用到了死鎖機制?
  • 5.0.0.5 ThreadLocal(線程變量副本)這個類的作用是什么?
  • 5.0.0.6 什么是線程安全?線程安全有那幾個級別?保障線程安全有哪些手段?ReentrantLock和synchronized的區別?
  • 5.0.0.7 Volatile和Synchronized各自用途是什么?有哪些不同點?Synchronize在編譯時如何實現鎖機制?
  • 5.0.0.8 wait()和sleep()的區別?各自有哪些使用場景?怎么喚醒一個阻塞的線程?Thread.sleep(0)的作用是啥?
  • 5.0.0.9 同步和非同步、阻塞和非阻塞的概念?分別有哪些使用場景?
  • 5.0.1.0 線程的有哪些狀態?請繪制該狀態的流程圖?講一下線程的執行生命周期流程?線程如果出現了運行時異常會怎么樣?
  • 5.0.1.1 synchronized鎖什么?synchronized同步代碼塊還有同步方法本質上鎖住的是誰?為什么?
  • 5.0.1.2 Volatile實現原理?一個int變量,用volatile修飾,多線程去操作++,線程安全嗎?那如何才能保證i++線程安全?
  • 5.0.1.3 CAS原理是什么?CAS實現原子操作會出現什么問題?
  • 5.0.1.4 假如有n個網絡線程,需要當n個網絡線程完成之后,再去做數據處理,你會怎么解決?
  • 5.0.1.5 Runnable接口和Callable接口的區別?
  • 5.0.1.6 如果提交任務時,線程池隊列已滿,這時會發生什么?線程調度算法是什么?
  • 5.0.1.7 什么是樂觀鎖和悲觀鎖?
  • 5.0.1.8 線程類的構造方法、靜態塊是被哪個線程調用的?同步方法和同步塊,哪個是更好的選擇?同步的范圍越少越好嗎?
  • 5.0.1.9 synchonized(this)和synchonized(object)區別?Synchronize作用于方法和靜態方法區別?

好消息

  • 博客筆記大匯總【15年10月到至今】,包括Java基礎及深入知識點,Android技術博客,Python學習筆記等等,還包括平時開發中遇到的bug匯總,當然也在工作之余收集了大量的面試題,長期更新維護并且修正,持續完善……開源的文件是markdown格式的!同時也開源了生活博客,從12年起,積累共計500篇[近100萬字],將會陸續發表到網上,轉載請注明出處,謝謝!
  • 鏈接地址:https://github.com/yangchong211/YCBlogs
  • 如果覺得好,可以star一下,謝謝!當然也歡迎提出建議,萬事起于忽微,量變引起質變!所有博客將陸續開源到GitHub!
5.0.0.1 線程池具有什么優點和缺點?為什么說開啟大量的線程,會降低程序的性能,那么該如何做才能降低性能?
  • 線程池好處:
    • 1)降低資源消耗;
    • 2)提高相應速度;
    • 3)提高線程的可管理性。技術博客大總結
  • 線程池的實現原理:
    • 當提交一個新任務到線程池時,判斷核心線程池里的線程是否都在執行。如果不是,則創建一個新的線程執行任務。如果核心線程池的線程都在執行任務,則進入下個流程。
    • 判斷工作隊列是否已滿。如果未滿,則將新提交的任務存儲在這個工作隊列里。如果工作隊列滿了,則進入下個流程。
    • 判斷線程池是否都處于工作狀態。如果沒有,則創建一個新的工作線程來執行任務。如果滿了,則交給飽和策略來處理這個任務。
5.0.0.3 線程中start和run方法有什么區別?wait和sleep方法的不同?sleep() 、join()、yield()有什么區別?
  • 線程中start和run方法有什么區別
    • 為什么我們調用start()方法時會執行run()方法,為什么我們不能直接調用run()方法?這是一個非常經典的java多線程面試問題。當你調用start()方法時你將創建新的線程,并且執行在run()方法里的代碼。但是如果你直接調用run()方法,它不會創建新的線程也不會執行調用線程的代碼。
  • wait和sleep方法的不同
    • 最大的不同是在等待時wait會釋放鎖,而sleep一直持有鎖。Wait通常被用于線程間交互,sleep通常被用于暫停執行。
  • 1、sleep()方法
    • 在指定的毫秒數內讓當前正在執行的線程休眠(暫停執行),此操作受到系統計時器和調度程序精度和準確性的影響。 讓其他線程有機會繼續執行,但它并不釋放對象鎖。也就是如果有Synchronized同步塊,其他線程仍然不能訪問共享數據。注意該方法要捕獲異常
    • 比如有兩個線程同時執行(沒有Synchronized),一個線程優先級為MAX_PRIORITY,另一個為MIN_PRIORITY,如果沒有Sleep()方法,只有高優先級的線程執行完成后,低優先級的線程才能執行;但當高優先級的線程sleep(5000)后,低優先級就有機會執行了。
    • 總之,sleep()可以使低優先級的線程得到執行的機會,當然也可以讓同優先級、高優先級的線程有執行的機會。
  • 2、yield()方法技術博客大總結
    • yield()方法和sleep()方法類似,也不會釋放“鎖標志”,區別在于,它沒有參數,即yield()方法只是使當前線程重新回到可執行狀態,所以執行yield()的線程有可能在進入到可執行狀態后馬上又被執行,另外yield()方法只能使同優先級或者高優先級的線程得到執行機會,這也和sleep()方法不同。
  • 3、join()方法
    • Thread的非靜態方法join()讓一個線程B“加入”到另外一個線程A的尾部。在A執行完畢之前,B不能工作。
    • Thread t = new MyThread(); t.start(); t.join();保證當前線程停止執行,直到該線程所加入的線程完成為止。然而,如果它加入的線程沒有存活,則當前線程不需要停止。
  • Thread的join()有什么作用?
    • Thread的join()的含義是等待該線程終止,即將掛起調用線程的執行,直到被調用的對象完成它的執行。比如存在兩個線程t1和t2,下述代碼表示先啟動t1,直到t1的任務結束,才輪到t2啟動。
      t1.start();
      t1.join(); 
      t2.start();
5.0.0.4 用Java手寫一個會導致死鎖的程序,遇到這種問題解決方案是什么?那些場景用到了死鎖機制?
  • 死鎖是怎么一回事
    • 線程A和線程B相互等待對方持有的鎖導致程序無限死循環下去。
  • 深入理解死鎖的原理
    • 兩個線程里面分別持有兩個Object對象:lock1和lock2。這兩個lock作為同步代碼塊的鎖;
    • 線程1的run()方法中同步代碼塊先獲取lock1的對象鎖,Thread.sleep(xxx),時間不需要太多,50毫秒差不多了,然后接著獲取lock2的對象鎖。這么做主要是為了防止線程1啟動一下子就連續獲得了lock1和lock2兩個對象的對象鎖
    • 線程2的run)(方法中同步代碼塊先獲取lock2的對象鎖,接著獲取lock1的對象鎖,當然這時lock1的對象鎖已經被線程1鎖持有,線程2肯定是要等待線程1釋放lock1的對象鎖的
5.0.0.5 ThreadLocal(線程變量副本)這個類的作用是什么?
  • ThreadLocal即線程變量
    • ThreadLocal為每個線程維護一個本地變量。
    • 采用空間換時間,它用于線程間的數據隔離,它為每個使用該變量的線程提供獨立的變量副本,所以每一個線程都可以獨立地改變自己的副本,而不會影響其它線程所對應的副本。從線程的角度看,目標變量就象是線程的本地變量,這也是類名中“Local”所要表達的意思。ThreadLocal的實現是以ThreadLocal對象為鍵。任意對象為值得存儲結構。這個結構被附帶在線程上,也就是說一個線程可以根據一個ThreadLocal對象查詢到綁定在這個線程上的一個值。
  • ThreadLocal類是一個Map
    • ThreadLocal類中維護一個Map,用于存儲每一個線程的變量副本,Map中元素的鍵為線程對象,而值為對應線程的變量副本。
    • ThreadLocal在Spring中發揮著巨大的作用,在管理Request作用域中的Bean、事務管理、任務調度、AOP等模塊都出現了它的身影。
    • Spring中絕大部分Bean都可以聲明成Singleton作用域,采用ThreadLocal進行封裝,因此有狀態的Bean就能夠以singleton的方式在多線程中正常工作了。
  • 更多詳細參考博客:深入研究java.lang.ThreadLocal類
5.0.0.6 什么是線程安全?線程安全有那幾個級別?保障線程安全有哪些手段?ReentrantLock和synchronized的區別?
  • 什么是線程安全
    • 線程安全就是當多個線程訪問一個對象時,如果不用考慮這些線程在運行時環境下的調度和交替執行,也不需要進行額外的同步,或者在調用方進行任何其他的協調操作,調用這個對象的行為都可以獲得正確的結果,那這個對象是線程安全的。
  • 線程安全也是有幾個級別
    • 技術博客大總結
    • 不可變:
      • 像String、Integer、Long這些,都是final類型的類,任何一個線程都改變不了它們的值,要改變除非新創建一個,因此這些不可變對象不需要任何同步手段就可以直接在多線程環境下使用
    • 絕對線程安全
      • 不管運行時環境如何,調用者都不需要額外的同步措施。要做到這一點通常需要付出許多額外的代價,Java中標注自己是線程安全的類,實際上絕大多數都不是線程安全的,不過絕對線程安全的類,Java中也有,比方說CopyOnWriteArrayList、CopyOnWriteArraySet
    • 相對線程安全
      • 相對線程安全也就是我們通常意義上所說的線程安全,像Vector這種,add、remove方法都是原子操作,不會被打斷,但也僅限于此,如果有個線程在遍歷某個Vector、有個線程同時在add這個Vector,99%的情況下都會出現ConcurrentModificationException,也就是fail-fast機制。
    • 線程非安全技術博客大總結
      • ArrayList、LinkedList、HashMap等都是線程非安全的類.
  • 保障線程安全有哪些手段。保證線程安全可從多線程三特性出發:
    • 原子性(Atomicity):單個或多個操作是要么全部執行,要么都不執行
      • Lock:保證同時只有一個線程能拿到鎖,并執行申請鎖和釋放鎖的代碼
      • synchronized:對線程加獨占鎖,被它修飾的類/方法/變量只允許一個線程訪問
    • 可見性(Visibility):當一個線程修改了共享變量的值,其他線程能夠立即得知這個修改
      • volatile:保證新值能立即同步到主內存,且每次使用前立即從主內存刷新;
      • synchronized:在釋放鎖之前會將工作內存新值更新到主存中
    • 有序性(Ordering):程序代碼按照指令順序執行
      • volatile: 本身就包含了禁止指令重排序的語義
      • synchronized:保證一個變量在同一個時刻只允許一條線程對其進行lock操作,使得持有同一個鎖的兩個同步塊只能串行地進入
  • ReentrantLock和synchronized的區別
    • ReentrantLock與synchronized的不同在于ReentrantLock:
      • 等待可中斷:當持有鎖的線程長期不釋放鎖的時候,正在等待的線程可以選擇放棄等待,改為處理其他事情。
      • 公平鎖:多個線程在等待同一個鎖時,必須按照申請鎖的時間順序來依次獲得鎖。而synchronized是非公平的,即在鎖被釋放時,任何一個等待鎖的線程都有機會獲得鎖。ReentrantLock默認情況下也是非公平的,但可以通過帶布爾值的構造函數改用公平鎖。
      • 鎖綁定多個條件:一個ReentrantLock對象可以通過多次調用newCondition()同時綁定多個Condition對象。而在synchronized中,鎖對象wait()和notify()或notifyAl()只能實現一個隱含的條件,若要和多于一個的條件關聯不得不額外地添加一個鎖。
    • Synchronized是悲觀鎖機制,獨占鎖。而Locks.ReentrantLock是,每次不加鎖而是假設沒有沖突而去完成某項操作,如果因為沖突失敗就重試,直到成功為止。
      • ReentrantLock適用場景
      • 某個線程在等待一個鎖的控制權的這段時間需要中斷
      • 需要分開處理一些wait-notify,ReentrantLock里面的Condition應用,能夠控制notify哪個線程,鎖可以綁定多個條件。
      • 具有公平鎖功能,每個到來的線程都將排隊等候。
    • 更多詳細參考博客:Lock與synchronized 的區別
5.0.0.7 Volatile和Synchronized各自用途是什么?有哪些不同點?Synchronize在編譯時如何實現鎖機制?
  • Volatile和Synchronized各自用途是什么?有哪些不同點?
    • 1 粒度不同,前者針對變量 ,后者鎖對象和類
    • 2 syn阻塞,volatile線程不阻塞
    • 3 syn保證三大特性,volatile不保證原子性
    • 4 syn編譯器優化,volatile不優化 volatile具備兩種特性:
      • 1.保證此變量對所有線程的可見性,指一條線程修改了這個變量的值,新值對于其他線程來說是可見的,但并不是多線程安全的。
      • 2.禁止指令重排序優化。
    • Volatile如何保證內存可見性:
      • 1.當寫一個volatile變量時,JMM會把該線程對應的本地內存中的共享變量刷新到主內存。
      • 2.當讀一個volatile變量時,JMM會把該線程對應的本地內存置為無效。線程接下來將從主內存中讀取共享變量。
    • 同步:就是一個任務的完成需要依賴另外一個任務,只有等待被依賴的任務完成后,依賴任務才能完成。
    • 異步:不需要等待被依賴的任務完成,只是通知被依賴的任務要完成什么工作,只要自己任務完成了就算完成了,被依賴的任務是否完成會通知回來。(異步的特點就是通知)。 打電話和發短信來比喻同步和異步操作。
    • 阻塞:CPU停下來等一個慢的操作完成以后,才會接著完成其他的工作。
    • 非阻塞:非阻塞就是在這個慢的執行時,CPU去做其他工作,等這個慢的完成后,CPU才會接著完成后續的操作。
    • 非阻塞會造成線程切換增加,增加CPU的使用時間能不能補償系統的切換成本需要考慮。
  • Synchronize在編譯時如何實現鎖機制?
    • Synchronized進過編譯,會在同步塊的前后分別形成monitorenter和monitorexit這個兩個字節碼指令。在執行monitorenter指令時,首先要嘗試獲取對象鎖。如果這個對象沒被鎖定,或者當前線程已經擁有了那個對象鎖,把鎖的計算器加1,相應的,在執行monitorexit指令時會將鎖計算器就減1,當計算器為0時,鎖就被釋放了。如果獲取對象鎖失敗,那當前線程就要阻塞,直到對象鎖被另一個線程釋放為止。
5.0.0.8 wait()和sleep()的區別?各自有哪些使用場景?怎么喚醒一個阻塞的線程?Thread.sleep(0)的作用是啥?
  • sleep來自Thread類,和wait來自Object類
    • 調用sleep()方法的過程中,線程不會釋放對象鎖。而調用wait方法線程會釋放對象鎖
    • sleep睡眠后不出讓系統資源,wait讓出系統資源其他線程可以占用CPU
    • sleep(milliseconds)需要指定一個睡眠時間,時間一到會自動喚醒
  • 通俗解釋
    • Java程序中wait 和 sleep都會造成某種形式的暫停,它們可以滿足不同的需要。wait()方法用于線程間通信,如果等待條件為真且其它線程被喚醒時它會釋放鎖,而 sleep()方法僅僅釋放CPU資源或者讓當前線程停止執行一段時間,但不會釋放鎖。
  • 怎么喚醒一個阻塞的線程?
    • 如果線程是因為調用了wait()、sleep()或者join()方法而導致的阻塞,可以中斷線程,并且通過拋出InterruptedException來喚醒它;如果線程遇到了IO阻塞,無能為力,因為IO是操作系統實現的,Java代碼并沒有辦法直接接觸到操作系統。
    • 技術博客大總結
  • Thread.sleep(0)的作用是啥?
    • 由于Java采用搶占式的線程調度算法,因此可能會出現某條線程常常獲取到CPU控制權的情況,為了讓某些優先級比較低的線程也能獲取到CPU控制權,可以使用Thread.sleep(0)手動觸發一次操作系統分配時間片的操作,這也是平衡CPU控制權的一種操作。
5.0.0.9 同步和非同步、阻塞和非阻塞的概念?分別有哪些使用場景?
  • 同步和非同步
    • 同步和異步體現的是消息的通知機制:所謂同步,方法A調用方法B后必須等到方法B返回結果才能繼續后面的操作;所謂異步,方法A調用方法B后可讓方法B在調用結束后通過回調等方式通知方法A
  • 阻塞和非阻塞
    • 阻塞和非阻塞側重于等待消息時的狀態:所謂阻塞,就是在結果返回之前讓當前線程掛起;所謂非阻塞,就是在等待時可做其他事情,通過輪詢去詢問是否已返回結果
5.0.1.0 線程的有哪些狀態?請繪制該狀態的流程圖?講一下線程的執行生命周期流程?線程如果出現了運行時異常會怎么樣?
  • 在任意一個時間點,一個線程只能有且只有其中的一種狀態
    • 新建(New):線程創建后尚未啟動
    • 技術博客大總結
    • 運行(Runable):包括正在執行(Running)和等待著CPU為它分配執行時間(Ready)兩種
      無限期等待(Waiting):該線程不會被分配CPU執行時間,要等待被其他線程顯式地喚醒。以下方法會讓線程陷入無限期等待狀態:
      沒有設置Timeout參數的Object.wait()
      沒有設置Timeout參數的Thread.join()
      LockSupport.park()
    • 限期等待(Timed Waiting):該線程不會被分配CPU執行時間,但在一定時間后會被系統自動喚醒。以下方法會讓線程進入限期等待狀態:
      Thread.sleep()
      設置了Timeout參數的Object.wai()
      設置了Timeout參數的Thread.join()
      LockSupport.parkNanos()
      LockSupport.parkUntil()
    • 阻塞(Blocked):線程被阻塞。和等待狀態不同的是,阻塞狀態表示在等待獲取到一個排他鎖,在另外一個線程放棄這個鎖的時候發生;而等待狀態表示在等待一段時間或者喚醒動作的發生,在程序等待進入同步區域的時候發生。
    • 結束(Terminated):線程已經結束執行
  • 繪制該狀態的流程圖
  • 線程如果出現了運行時異常會怎么樣?
    • 如果這個異常沒有被捕獲的話,這個線程就停止執行了。另外重要的一點是:如果這個線程持有某個某個對象的監視器,那么這個對象監視器會被立即釋放
5.0.1.1 synchronized鎖什么?synchronized同步代碼塊還有同步方法本質上鎖住的是誰?為什么?
  • synchronized鎖什么
    • 對于普通同步方法,鎖是當前實例對象;
    • 對于靜態同步方法,鎖是當前類的Class對象;
    • 對于同步方法塊,鎖是括號中配置的對象;
    • 當一個線程試圖訪問同步代碼塊時,它首先必須得到鎖,退出或拋出異常時必須釋放鎖。synchronized用的鎖是存在Java對象頭里的MarkWord,通常是32bit或者64bit,其中最后2bit表示鎖標志位。
  • 本質上鎖住的是對象。
    • 在java虛擬機中,每個對象和類在邏輯上都和一個監視器相關聯,synchronized本質上是對一個對象監視器的獲取。當執行同步代碼塊或同步方法時,執行方法的線程必須先獲得該對象的監視器,才能進入同步代碼塊或同步方法;而沒有獲取到的線程將會進入阻塞隊列,直到成功獲取對象監視器的線程執行結束并釋放鎖后,才會喚醒阻塞隊列的線程,使其重新嘗試對對象監視器的獲取。
5.0.1.2 Volatile實現原理?一個int變量,用volatile修飾,多線程去操作++,線程安全嗎?那如何才能保證i++線程安全?
  • volatile的作用和原理
    • Java代碼在編譯后會變成Java字節碼,字節碼被類加載器加載到JVM里,JVM執行字節碼,最終需要轉化為匯編指令在CPU上執行。
    • volatile是輕量級的synchronized(volatile不會引起線程上下文的切換和調度),它在多處理器開發中保證了共享變量的“可見性”。可見性的意思是當一個線程修改一個共享變量時,另外一個線程能讀到這個修改的值。
    • 由于內存訪問速度遠不及CPU處理速度,為了提高處理速度,處理器不直接和內存進行通信,而是先將系統內存的數據讀到內部緩存后在進行操作,但操作完不知道何時會寫到內存。普通共享變量被修改之后,什么時候被寫入主存是不確定的,當其他線程去讀取時,此時內存中可能還是原來的舊值,因此無法保證可見性。如果對聲明了volatile的變量進行寫操作,JVM就會想處理器發送一條Lock前綴的指令,表示將當前處理器緩存行的數據寫回到系統內存。
  • 一個int變量,用volatile修飾,多線程去操作++,線程安全嗎
    • 技術博客大總結
    • 不安全
    • 案例代碼,至于打印結果就不展示呢
    • volatile只能保證可見性,并不能保證原子性。
    • i++實際上會被分成多步完成:
      • 1)獲取i的值;
      • 2)執行i+1;
      • 3)將結果賦值給i。
    • volatile只能保證這3步不被重排序,多線程情況下,可能兩個線程同時獲取i,執行i+1,然后都賦值結果2,實際上應該進行兩次+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。其實現原理是采用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實現原子操作會出現什么問題?
  • CAS原理是什么
    • CAS即compare and swap的縮寫,中文翻譯成比較并交換。CAS有3個操作數,內存值V,舊的預期值A,要修改的新值B。當且僅當預期值A和內存值V相同時,將內存值V修改為B,否則什么都不做。自旋就是不斷嘗試CAS操作直到成功為止。
  • CAS實現原子操作會出現什么問題
    • ABA問題。因為CAS需要在操作之的時候,檢查值有沒有發生變化,如果沒有發生變化則更新,但是如果一個值原來是A,變成,有變成A,那么使用CAS進行檢查時會發現它的值沒有發生變化,但實際上發生了變化。ABA問題可以通過添加版本號來解決。Java 1.5開始,JDK的Atomic包里提供了一個類AtomicStampedReference來解決ABA問題。
    • 循環時間長開銷大。pause指令優化。
    • 只能保證一個共享變量的原子操作。可以合并成一個對象進行CAS操作。
5.0.1.4 假如有n個網絡線程,需要當n個網絡線程完成之后,再去做數據處理,你會怎么解決?
  • 多線程同步的問題。這種情況可以可以使用thread.join();join方法會阻塞直到thread線程終止才返回。更復雜一點的情況也可以使用CountDownLatch,CountDownLatch的構造接收一個int參數作為計數器,每次調用countDown方法計數器減一。做數據處理的線程調用await方法阻塞直到計數器為0時。
5.0.1.5 Runnable接口和Callable接口的區別?
  • Runnable接口和Callable接口的區別
    • Runnable接口中的run()方法的返回值是void,它做的事情只是純粹地去執行run()方法中的代碼而已;Callable接口中的call()方法是有返回值的,是一個泛型,和Future、FutureTask配合可以用來獲取異步執行的結果。
    • 這其實是很有用的一個特性,因為多線程相比單線程更難、更復雜的一個重要原因就是因為多線程充滿著未知性,某條線程是否執行了?某條線程執行了多久?某條線程執行的時候我們期望的數據是否已經賦值完畢?無法得知,我們能做的只是等待這條多線程的任務執行完畢而已。而Callable+Future/FutureTask卻可以獲取多線程運行的結果,可以在等待時間太長沒獲取到需要的數據的情況下取消該線程的任務,真的是非常有用。
5.0.1.6 如果提交任務時,線程池隊列已滿,這時會發生什么?線程調度算法是什么?
  • 如果提交任務時,線程池隊列已滿,這時會發生什么?
    • 如果使用的是×××隊列LinkedBlockingQueue,也就是×××隊列的話,沒關系,繼續添加任務到阻塞隊列中等待執行,因為LinkedBlockingQueue可以近乎認為是一個無窮大的隊列,可以無限存放任務
    • 技術博客大總結
    • 如果使用的是有界隊列比如ArrayBlockingQueue,任務首先會被添加到ArrayBlockingQueue中,ArrayBlockingQueue滿了,會根據maximumPoolSize的值增加線程數量,如果增加了線程數量還是處理不過來,ArrayBlockingQueue繼續滿,那么則會使用拒絕策略RejectedExecutionHandler處理滿了的任務,默認是AbortPolicy
  • 線程調度算法是什么?
    • 搶占式。一個線程用完CPU之后,操作系統會根據線程優先級、線程饑餓情況等數據算出一個總的優先級并分配下一個時間片給某個線程執行。
5.0.1.7 什么是樂觀鎖和悲觀鎖?
  • 什么是樂觀鎖和悲觀鎖?
    • 樂觀鎖:就像它的名字一樣,對于并發間操作產生的線程安全問題持樂觀狀態,樂觀鎖認為競爭不總是會發生,因此它不需要持有鎖,將比較-替換這兩個動作作為一個原子操作嘗試去修改內存中的變量,如果失敗則表示發生沖突,那么就應該有相應的重試邏輯。
    • 悲觀鎖:還是像它的名字一樣,對于并發間操作產生的線程安全問題持悲觀狀態,悲觀鎖認為競爭總是會發生,因此每次對某資源進行操作時,都會持有一個獨占的鎖,就像synchronized,直接上了鎖就操作資源。
5.0.1.8 線程類的構造方法、靜態塊是被哪個線程調用的?同步方法和同步塊,哪個是更好的選擇?同步的范圍越少越好嗎?
  • 線程類的構造方法、靜態塊是被哪個線程調用的?
    • 線程類的構造方法、靜態塊是被new這個線程類所在的線程所調用的,而run方法里面的代碼才是被線程自身所調用的。
  • 舉個例子
    • 假設Thread2中new了Thread1,main函數中new了Thread2,那么:
      • Thread2的構造方法、靜態塊是main線程調用的,Thread2的run()方法是Thread2自己調用的
      • Thread1的構造方法、靜態塊是Thread2調用的,Thread1的run()方法是Thread1自己調用的
  • 同步方法和同步塊,哪個是更好的選擇?
    • 同步塊,這意味著同步塊之外的代碼是異步執行的,這比同步整個方法更提升代碼的效率。請知道一條原則:同步的范圍越小越好。
    • 技術博客大總結
  • 同步的范圍越少越好嗎?
    • 是的。雖說同步的范圍越少越好,但是在Java虛擬機中還是存在著一種叫做鎖粗化的優化方法,這種方法就是把同步范圍變大。這是有用的,比方說StringBuffer,它是一個線程安全的類,自然最常用的append()方法是一個同步方法,我們寫代碼的時候會反復append字符串,這意味著要進行反復的加鎖->解鎖,這對性能不利,因為這意味著Java虛擬機在這條線程上要反復地在內核態和用戶態之間進行切換,因此Java虛擬機會將多次append方法調用的代碼進行一個鎖粗化的操作,將多次的append的操作擴展到append方法的頭尾,變成一個大的同步塊,這樣就減少了加鎖-->解鎖的次數,有效地提升了代碼執行的效率。
5.0.1.9 synchonized(this)和synchonized(object)區別?Synchronize作用于方法和靜態方法區別?
  • synchonized(this)和synchonized(object)區別技術博客大總結
    • 其實并沒有很大的區別,synchonized(object)本身就包含synchonized(this)這種情況,使用的場景都是對一個代碼塊進行加鎖,效率比直接在方法名上加synchonized高一些(下面分析),唯一的區別就是對象的不同。
    • 對synchronized(this)的一些理解
      • 一、當兩個并發線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內只能有一個線程得到執行。另一個線程必須等待當前線程執行完這個代碼塊以后才能執行該代碼塊。
      • 二、然而,當一個線程訪問object的一個synchronized(this)同步代碼塊時,另一個線程仍然可以訪問該object中的非synchronized(this)同步代碼塊。
      • 三、尤其關鍵的是,當一個線程訪問object的一個synchronized(this)同步代碼塊時,其他線程對object中所有其它synchronized(this)同步代碼塊的訪問將被阻塞。
      • 四、當一個線程訪問object的一個synchronized(this)同步代碼塊時,它就獲得了這個object的對象鎖。結果,其它線程對該object對象所有同步代碼部分的訪問都被暫時阻塞。
  • Synchronize作用于方法和靜態方法區別

    • 測試代碼如下所示

      
      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();
        }
    }

    }

    //調用method01方法打印日志【普通方法】
    tag a set number over
    tag b set number over
    tag = b;num =200
    tag = a;num =100

    //調用method02方法打印日志【static靜態方法】
    tag a set number over
    tag = a;num =100
    tag b set number over
    tag = b;num =200

    
    - 在static方法前加synchronized:靜態方法屬于類方法,它屬于這個類,獲取到的鎖,是屬于類的鎖。 
    - 在普通方法前加synchronized:非static方法獲取到的鎖,是屬于當前對象的鎖。 [技術博客大總結](https://github.com/yangchong211/YCBlogs)
    - 結論:類鎖和對象鎖不同,synchronized修飾不加static的方法,鎖是加在單個對象上,不同的對象沒有競爭關系;修飾加了static的方法,鎖是加載類上,這個類所有的對象競爭一把鎖。

其他介紹

01.關于博客匯總鏈接
  • 1.技術博客匯總
  • 2.開源項目匯總
  • 3.生活博客匯總
  • 4.喜馬拉雅音頻匯總
  • 5.其他匯總
02.關于我的博客
  • 我的個人站點:www.yczbj.org,www.ycbjie.cn
  • github:https://github.com/yangchong211
  • 知乎:https://www.zhihu.com/people/yang-chong-69-24/pins/posts
  • 簡書:http://www.jianshu.com/u/b7b2c6ed9284
  • csdn:http://my.csdn.net/m0_37700275
  • 喜馬拉雅聽書:http://www.ximalaya.com/zhubo/71989305/
  • 開源中國:https://my.oschina.net/zbj1618/blog
  • 泡在網上的日子: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
向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

平遥县| 钟祥市| 曲靖市| 绥阳县| 远安县| 平顶山市| 铁岭市| 乌兰浩特市| 闽侯县| 昌吉市| 兴义市| 鄂温| 九龙县| 辉南县| 大关县| 镇宁| 阳信县| 筠连县| 英吉沙县| 巴彦淖尔市| 松潘县| 开江县| 孟津县| 社旗县| 苍山县| 淅川县| 陈巴尔虎旗| 涡阳县| 河间市| 冕宁县| 马山县| 宁波市| 台湾省| 安陆市| 庄河市| 酒泉市| 盐源县| 广宗县| 灌南县| 黄陵县| 尖扎县|