日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

无招胜有招之多线程

發布時間:2024/2/28 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 无招胜有招之多线程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

? ? ? ?并發和并行的區別:

解釋一:并行是指兩個或者多個事件在同一時刻發生;而并發是指兩個或多個事件在同一時間間隔發生。

解釋二:并行是在不同實體上的多個事件,并發是在同一實體上的多個事件。

解釋三:并行是在一臺處理器上“同時”處理多個任務,并發是在多臺處理器上同時處理多個任務。如 hadoop 分布式集群。

  • 線程和進程的區別

線程和進程一樣,都是實現并發的一個基本單位。但線程是比進程更小的執行單位,線程是在進程的基礎之上進行的進一步劃分。多線程指一個進程在執行過程中可以產生多個更小的程序單元,這些更小的單元稱為線程

進程是程序的一次動態執行過程,他需要經歷從代碼加載、代碼執行到執行完畢的一個完整過程,這個過程也是程序本身從產生、發展到最終消亡的過程。每一個運行的程序就是一個進程,一般而言,進程在系統中獨立存在,擁有自己獨立的資源。

  • 線程的實現、線程的狀態、優先級、線程調度、創建線程的多種方式、守護線程

  • 線程的實現(創建線程的多種方式)
  • 三種實現線程的方式:

  • 繼承Thread類創建線程
  • 實現Runnable接口創建線程(使用Thread.currentThread()訪問當前線程)
  • 使用Callable接口和Future接口創建線程(有返回值、使用Thread.currentThread()訪問當前線程)
  • 線程的狀態(生命周期)
  • ?

    新建狀態(new-》就緒狀態(start)-》運行狀態(獲得CPU使用權)-》阻塞狀態(因為某些原因放棄CPU,暫時停止運行)-》死亡狀態(run正常執行完成、線程出現異常或錯誤、調用了線程的stop方法)

    線程一旦死亡,不能運行且不能轉換為其他形態。

    【補充】yield不會是線程阻塞,只是將線程轉換為就緒狀態,也就是讓線程暫停一下,線程調度器重新調度一次,有可能還會將暫停的程序調度出來繼續執行,這就是線程讓步。

  • 優先級
  • 所有處于就緒狀態的線程根據優先級存放在可運行池中,優先級低的運行機會較少,優先級高的運行機會更多。

    Thread的setPriority(int newPriority)方法和getPriority()方法用來設置優先級和讀取優先級。

  • 線程調度
  • 如果一個計算機只有一個CPU,那么在任意時刻只能執行一條指令,每個線程只能獲得CPU使用權才能執行指令。從宏觀上看,多線程的并發運行是每一個線程輪流獲得CPU的使用權,分別執行各自的任務。但在運行池中,會有多個處于就緒狀態的線程在等待CPU,JVM的一項任務就是負責線程的調度,即按照特定的機制為多個線程分配CPU使用權。調度模型分為分時調度模型和搶占式調度模型兩種

    分時調度模型是讓所有線程輪流獲取CPU使用權,平均分配每一個線程占用CPU的時間片。搶占式調度模型是優先讓可運行池中優先級高的線程占用CPU,若運行池中線程優先級相同,則隨機選擇一個線程使用CPU,當它失去CPU使用權時,再隨機選取一個線程獲得CPU使用權。JAVA默認使用搶占式調度模型。

  • 守護線程
  • ?? 又稱后臺線程,JVM的垃圾回收線程就是典型的后臺線程。即如果前臺線程都死亡, 后臺線程會自動死亡。當整個虛擬機中只剩下后臺線程,程序就沒有繼續運行的必要了, 所以JVM就退出了。

    可以調用Thread中的setDaemon(true)。將線程設置為守護線程。另外,Thread類還提供了isDaemon()用于判斷線程是否是守護線程。

    • 自己設計線程池、submit() 和execute()、 線程池原理

  • 自己設計線程池
  • https://blog.csdn.net/iterzebra/article/details/6758481

  • submit() 和execute()
  • ExecutorService中submit()和execute()的區別

    1execute()Executor接口中的方法:

    public?interface?Executor {

    ????void?execute(Runnable command);

    }

    ?

    execute()方法的入參為一個Runnable,返回值為void

  • submit()方法ExecutorService接口中的方法:
  • public interface ExecutorService extends Executor {

      ...

      <T> Future<T> submit(Callable<T> task);

    ?

      <T> Future<T> submit(Runnable task, T result);

    ?

      Future<?> submit(Runnable task);

      ...

    }

    submit()方法入參可以為Callable<T>,也可以為Runnable,而且方法有返回值Future<T>

    execute()和submit()方法的區別:

    1.?接收的參數不一樣;

    2.?submit()有返回值,而execute()沒有;

    例如,有個validation的task,希望該task執行完后告訴我它的執行結果,是 成功還是失敗,然后繼續下面的操作。

    3.?submit()可以進行Exception處理;

    例如,如果task里會拋出checked或者unchecked exception,而你又希望 外面的調用者能夠感知這些exception并做出及時的處理,那么就需要用到submit,通 過對 Future.get()進行拋出異常的捕獲,然后對其進行處理。

  • 線程池原理
  • 程序啟動一個新線程的成本是比較高的,因為它涉及要與才做系統進行交互。而使用線程池可以很好地提高性能,尤其是當程序中需要創建大量生存期很短的線程時,更應該考慮到線程池,線程池中的每一個線程代碼結束后,并不會死亡,而是再次回到線程池中成為空閑狀態,等待下一個對象來使用。

    使用線程池好處:1.降低資源消耗2.提高響應速度3.提高線程的可管理性

    • 為什么不允許使用Executors創建線程池

    線程池不允許使用Executors去創建,而是通過ThreadPoolExecutor的方式,這樣的處理方式讓寫的同學更加明確線程池的運行規則,規避資源耗盡的風險。

    • 死鎖、死鎖如何排查、線程安全和內存模型的關系

    不同線程分別占用對方需要的同步資源不放棄,都在等待對方放棄自己需要的同步資源,就形成了線程的死鎖。

    排查:

  • 使用 jps + jstack(第一:在windons命令窗口,使用 jps -l?第二:使用jstack -l 12316?)
  • 使用jconsole,在window打開 JConsole,JConsole是一個圖形化的監控工具!(在windons命令窗口 ,輸出 JConsole)
  • 使用Java Visual VM
  • 在window打開 jvisualvm,jvisualvm是一個圖形化的監控工具!

    在windons命令窗口 ,輸出 jvisualvm

    線程安全和內存模型的關系

    https://blog.csdn.net/mikeoperfect/article/details/79133899

    • ThreadLocal變量

    線程相關類ThreadLocal并非一個線程Thread,而是ThreadLocalVariable(線程局部變量),ThreadLocal功用非常簡單,就是為每一個使用該變量的線程都提供一個變量值的副本,是java中一種較為特殊的線程綁定機制,是每一個線程都可以獨立改變自己的副本,而不會和其他線程副本沖突。

    核心意思:ThreadLocal 提供了線程本地的實例。它與普通變量的區別在于,每個使用該變量的線程都會初始化一個完全獨立的實例副本。ThreadLocal 變量通常被private static修飾。當一個線程結束時,它所使用的所有 ThreadLocal 相對的實例副本都可被回收。

    【補充:】在Spring中的單例Bean的線程安全問題。

    兩種解決方案:

    1.在Bean對象中盡量避免定義可變的成員變量(不太現實)。

    2.在類中定義一個ThreadLocal成員變量,將需要的可變成員變量保存在 ThreadLocal 中(推薦的一種方式)。

    ?

    • Executor創建線程池的幾種方式:

    newFixedThreadPool(int nThreads)創建一個可重用固定線程數的線程池,以共享的無界隊列方式來運行這些線程。

    newCachedThreadPool()創建一個可根據需要創建新線程的線程池,在以前構造的線程可用時將重用它們。

    newSingleThreadExecutor()創建一個使用單個worker線程的Executor,以無界隊列方式來運行該線程。

    newScheduledThreadP ool(int corePoolSize)創建一個線程池,可以調度命令在給定的延遲之后運行,或定期執行。

    【補充】

    有界隊列:就是有固定大小的隊列。比如設定了固定大小的 LinkedBlockingQueue,又或者大小為 0,只是在生產者和消費者中做中轉用的 SynchronousQueue。

    無界隊列:指的是沒有設置固定大小的隊列。這些隊列的特點是可以直接入列,直到溢出。當然現實幾乎不會有到這么大的容量(超過 Integer.MAX_VALUE),所以從使用者的體驗上,就相當于 “無界”。比如沒有設定固定大小的 LinkedBlockingQueue。

    • ThreadPoolExecutor創建線程池、拒絕策略

    ?

    拿最后一個為例:

    ?

    拒絕策略:

    1.AbortPolicy

    該策略是線程池的默認策略。使用該策略時,如果線程池隊列滿了丟掉這個任務并且拋出RejectedExecutionException異常。

    2.DiscardPolicy

    這個策略和AbortPolicy的slient版本,如果線程池隊列滿了,會直接丟掉這個任務并且不會有任何異常。

    3.DiscardOldestPolicy

    這個策略從字面上也很好理解,丟棄最老的。也就是說如果隊列滿了,會將最早進入隊列的任務刪掉騰出空間,再嘗試加入隊列。
    因為隊列是隊尾進,隊頭出,所以隊頭元素是最老的,因此每次都是移除對頭元素后再嘗試入隊。

    4.CallerRunsPolicy

    使用此策略,如果添加到線程池失敗,那么主線程會自己去執行該任務,不會等待線程池中的線程去執行。就像是個急脾氣的人,我等不到別人來做這件事就干脆自己干。

    5.自定義拒絕策略

    實現RejectedExecutionHandler接口

    • 線程池關閉的方式

    Java提供的對ExecutorService的關閉方式有兩種,一種是調用其shutdown()方法,另一種是調用shutdownNow()方法。這兩者是有區別的。

    shutdown:

    1、調用之后不允許繼續往線程池內繼續添加線程;

    2、線程池的狀態變為SHUTDOWN狀態;

    3、所有在調用shutdown()方法之前提交到ExecutorSrvice的任務都會執行;

    4、一旦所有線程結束執行當前任務,ExecutorService才會真正關閉。

    shutdownNow():

    1、該方法返回尚未執行的 task 的 List;

    2、線程池的狀態變為STOP狀態;

    3、阻止所有正在等待啟動的任務, 并且停止當前正在執行的任務。

    簡單點來說,就是:

    shutdown()調用后,不可以再 submit 新的 task,已經 submit 的將繼續執行

    shutdownNow()調用后,試圖停止當前正在執行的 task,并返回尚未執行的 task 的 list

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    總結

    以上是生活随笔為你收集整理的无招胜有招之多线程的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。