Java多線程學習

      網友投稿 791 2025-03-31

      1. 多線程

      1.1概念

      多線程的概念

      程序、進程與線程:

      程序:一段靜態的代碼,它是應用軟件執行的藍本。

      進程:程序的一次動態執行過程(動態概念),它對應了從代碼加載、執行到執行完畢的完整過程。一個程序可以被多次加載到系統的不同區域分別執行,形成不同的進程。

      線程:比進程更小的執行單位(動態概念)。一個進程在執行過程中可產生多個線程,形成多條執行線索。每個進程都有一段專用的內存區,并以PCB(Process Control Block)作為它存在的標志;而一個進程中的所有線程可以共享該進程的同一個地址空間和操作系統資源,并利用這些共享單元實現數據交換、實時通信與必要的同步操作。因此多線程占用系統資源少、線程間通信快。

      1.2線程的生命周期

      線程是一個動態執行的過程,它也有一個從產生到死亡的過程。下圖顯示的是線程的生命周期

      1.2.1 新建狀態:

      使用 new 關鍵字和 Thread 類或其子類建立一個線程對象后,該線程對象就處于新建狀態。它保持這個狀態直到程序 start() 這個線程。

      1.2.2 就緒狀態

      當線程對象調用了start()方法之后,該線程就進入就緒狀態。就緒狀態的線程處于就緒隊列中,要等待JVM里線程調度器的調度。

      1.2.3 運行狀態

      如果就緒狀態的線程獲取 CPU 資源,就可以執行 run(),此時線程便處于運行狀態。處于運行狀態的線程最為復雜,它可以變為阻塞狀態、就緒狀態和死亡狀態。

      1.2.4 阻塞狀態

      如果一個線程執行了sleep(睡眠)、suspend(掛起)等方法,失去所占用資源之后,該線程就從運行狀態進入阻塞狀態。在睡眠時間已到或獲得設備資源后可以重新進入就緒狀態。可以分為三種:

      1.2.5 等待阻塞

      Java多線程學習

      運行狀態中的線程執行 wait() 方法,使線程進入到等待阻塞狀態。

      1.2.6 同步阻塞

      線程在獲取 synchronized 同步鎖失敗(因為同步鎖被其他線程占用)。

      1.2.7 其他阻塞

      通過調用線程的 sleep() 或 join() 發出了 I/O 請求時,線程就會進入到阻塞狀態。當sleep() 狀態超時,join() 等待線程終止或超時,或者 I/O 處理完畢,線程重新轉入就緒狀態。

      1.2.8 死亡狀態

      一個運行狀態的線程完成任務或者其他終止條件發生時,該線程就切換到終止狀態。

      1.3線程優先級

      每一個 Java 線程都有一個優先級,這樣有助于操作系統確定線程的調度序。

      Java 線程的優先級是一個整數,其取值范圍是 1 (Thread.MIN_PRIORITY ) - 10 (Thread.MAX_PRIORITY )。默認情況下,每一個線程都會分配一個優先級 NORM_PRIORITY(5)。

      具有較高優先級的線程對程序更重要,并且應該在低優先級的線程之前分配處理器資源。但是,線程優先級不能保證線程執行的順序,而且非常依賴于平臺。

      2. 多線程實現

      2.1 繼承Thread類

      通過定義java.lang包中的Thread類的子類并在子類中重寫run()方法。由于java不能多重繼承,此方法簡單但不靈活。Thread類的構造函數及主要方法如下:

      public Thread():產生一個名字自動生成的線程,名字形式為Thread_1、Thread_2、、、;

      public Thread(Runnable target):生成一個指定目標對象的線程;

      public Thread(String name):生成一個指定名字的線程;

      public Thread(ThreadGroup group,Runnable target):生成一個指定線程組和目標對象的線程;

      public Thread(ThreadGroup group,String name):生成一個指定線程組和名字的線程。

      通過繼承Thread類實現多線程示例:ThreadTest.java程序中subThread類繼承了Thread類,先定義了一個構造函數調用父類的構造函數給該線程置名,然后重寫了run()方法,使線程運行時每輸出一個循環變量后休眠一段隨機時間,讓另一個線程運行,一個線程的run()方法結束前輸出該線程的結束信息。

      2.2 實現Runnable接口

      Runnable接口只有一個run()方法,要實現此接口就必須定義run()方法的具體內容,方法體內可定義用戶要做的操作。然后以這個實現了Runnable接口的類為參數創建Thread類的對象,也就是用Runnable接口的目標對象初始化Thread類的對象,如此就可把用戶實現的run()方法繼承過來。

      創建一個線程,最簡單的方法是創建一個實現Runnable接口的類。

      為了實現Runnable,一個類只需要執行一個方法調用run(),聲明如下:

      Public void run();

      在創建一個實現Runnable接口的類之后,你可以在類中實例化一個線程對象。

      Thread(Runnable threadOb,String threadName);

      threadOb 是一個實現Runnable接口的類的實例,并且threadName指定新線程的名字。

      新線程創建之后,調用start()方法才會運行。

      void start();

      2.3 通過Callable和Future創建線程

      創建Callable接口的實現類,并實現call()方法,該call()方法將作為線程執行體,并有返回值。

      創建Callable實現類的實例,使用FutureTask類來包裝Callable對象,該FutureTask對象封裝了該Callable對象的call()方法的返回值。

      使用FutureTask對象作為Thread對象的target創建并啟動新線程。

      調用FutureTask對象的get()方法來獲得子線程執行結束后的返回值。

      3. 多線程的基本控制

      在控制線程從一種狀態轉入另一種狀態時,必須調用正確的方法,否則將產生異常。除了注意狀態轉換時需調用的方法外,為使多個線程之間能協調工作,必須控制線程的互斥、同步及死鎖問題。

      3.1互斥

      一組并發進程中一個或多個程序段,因共享某一公用資源而導致它們必須以一個不允許交叉執行的單位執行。即不允許兩個以上共享該公用資源的并發進程同時進入臨界區。

      3.2同步

      一組并發進程因直接制約而互相發送消息,進行相互合作,互相等待,使得各進程按一定的執行速度執行的過程,稱為進程間同步。

      3.3死鎖

      在多個進程并行執行時,當某進程提出資源申請后,使得若干進程在無外力作用下,永遠得不到所需要的資源,不能再繼續運行的情況。

      如生產者與消費者問題:生產的產品存入倉庫,消費時從倉庫取出產品。當倉庫滿時再生產將無處可放,而當倉庫空時再消費將取不到產品。采用同步策略可協調生產與消費.。

      4. 線程通信

      4.1 線程通信機制

      線程間同步可以歸納為一個線程間通信的一個子集,線程通信是指兩個線程之間可以交換一些實時的數據信息。

      4.2 實現線程間的通信方法(wait/notify,Lock/Condition)

      線程通信的wait和notify機制

      - 等待/通知機制

      - wait就是線程在獲取對象鎖后,主動釋放對象鎖,同時本線程休眠。知道線程調用notify喚醒該線程,才能繼續獲取對象鎖,繼續執行

      - 都是Object類的方法

      線程通信的Lock和Condition機制

      -Lock用于控制多線程對需要競爭的共享資源的順序訪問,保證狀態連續性

      -Condition是java提供實現等待/通知的類,由Lock對象所創建

      -Condition中的wait方法相當于Object的wait方法,signal方法相當于Object的notify方法

      5.JUC并發包

      5.1 線程的ThreadLocal本地緩存對象

      ThreadLocal線程范圍內的共享變量:線程范圍內的共享變量,每個線程只能訪問自己的數據,不能訪問別的線程數據。

      每個線程調用全局ThreadLocal對象的set方法,就相當于往其內部的map中增加一條記錄,key分別是各自的線程,value是各自的set方法傳進去的值。

      5.2 線程的volatile關鍵字

      volatile關鍵字可以用來修飾字段(成員變量),就是告知程序任何對該變量的訪問均需要從共享內存中獲取,而對它的改變必須同步刷新回共享內存,它能保證所有線程對變量訪問的可見性。

      volatile的作用:使變量在多個線程間可見,但是無法保證原子性。需要注意的是一般volatile用于只針對多個線程可見的變量操作,并不能代替synchronized的同步功能。

      5.3 線程池的作用和應用

      線程池的作用:

      --1、降低資源消耗:通過重復利用已創建的線程降低線程創建和銷毀造成的消耗。

      --2、提高響應速度:當任務到達時,任務可以不需要等到線程創建就能立即執行。

      --3、提高線程的可管理行:線程是稀缺資源,如果無限制的創建,不僅會消耗系統消耗,還會降低系統的穩定性,使用線程池可以進行統一的分配,調優和監控。

      5.4 線程的同步工具類CountDownLatch

      CountDownLatch同步輔助類,在完成一組正在其他線程中執行的操作之前,它允許一個或多個線程一直等待:

      --1、CountDownLatch類是一個同步計數器,構造時傳入int參數,該參數就是計數器的初始值,每調用countDown()方法,計數器減1,計數器大于0時,await()方法會阻塞程序繼續執行。

      --2、由于調用了countDown()方法,所以在當前計數到達零之前,await()方法會一直受阻塞。之后,會釋放所有等待的線程,await()的所有后續調用都將立即返回。這種現象只出現一次,計數無法被重置。一個線程或者多個,等待另外N個線程完成某個事情之后才能執行。

      5.5 線程的同步工具類CyclicBarrier

      CyclicBarrier是一個同步輔助類,允許一組線程互相等待,直到到達某個公眾屏障點(common barrier point)。因為該barrier在釋放等待線程后可以重用,所以稱它為循環的battier。

      5.6 線程的同步工具類Semaphore

      Semaphore是一個計數信號量,它的本質是一個共享鎖,是基于AQS實現的,通過state變量來實現共享。通過調用acquire方法,對state值減去一,當調用release的時候,對state值加一。當state變量小于0的時候,在AQS隊列中阻塞等待。

      5.7 線程的交換類Exchanger

      Exchanger(交換者)是一個用于線程間協作的工具類,Exchanger用于進行線程間的數據交換。

      它提供一個同步點,在這個同步點,兩個線程可以交換彼此的數據。

      這兩個線程通過exchanger()交換數據。

      如果第一個線程先執行exchanger()方法,它會一直等待第二個線程也執行exchanger(),當兩個線程都到達同步點時,這兩個線程就可以交換數據,將本線程生產出來的數據傳遞給對方。

      5.8 線程的Fork/Join機制

      Fork/Join框架是Java7提供一個用于并行執行任務的框架,是一個把大任務分割成若干個小任務,最終匯總每個小任務結果后得到大任務結果的框架。

      分治法:把一個規模大的問題劃分為規模較小的子問題,然后分而治之,最后合并子問題的解得到原問題的解。

      6.常用線程池

      6.1 優勢

      線程池做的工作主要是控制運行的線程的數量,處理過程中將任務放入隊到,然后在線程創建后啟動這些任務,如果線程數量超過了最大數量超出數量的線程排隊等候,等其它線程執行完畢,再從隊列中取出任務來執行。

      他的主要特點為:線程復用:控制最大并發數:;管理線程。

      第一:降低資源消耗。通過重復利用己創建的線程降低線程創建和銷毀造成的消耗。

      第二:提高響應速度。當任務到達時,任務可以不需要的等到線程創建就能立即執行。

      第三:提高線程的可管理性。線程是稀缺資源,如果無限制的創建,不僅會消耗系統資源,還會降低系統的穩定性,使用線程池可以進行統一的分配,調優和監控

      6.2 四種線程池

      6.2.1 newSingleThreadExecutor

      創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。

      6.2.2 newFixedThreadPool

      創建一個定長線程池,可控制線程最大并發數,超出的線程會在隊列中等待。

      6.2.3 newScheduledThreadPool

      創建一個可定期或者延時執行任務的定長線程池,支持定時及周期性任務執行。

      6.2.4 newCachedThreadPool

      創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程。

      6.3 核心類

      ① int corePoolSize, 核心線程大小

      ② int maximumPoolSize,最大線程大小

      ③long keepAliveTime, 超過corePoolSize的線程多久不活動被銷毀時間

      ④TimeUnit unit,時間單位

      ⑤BlockingQueue workQueue 任務隊列

      ⑥ThreadFactory threadFactory 線程池工廠

      ⑦RejectedExecutionHandler handler 拒絕策略

      6.4線程池任務執行流程

      當線程池小于corePoolSize時,新提交任務將創建一個新線程執行任務,即使此時線程池中存在空閑線程。

      當線程池達到corePoolSize時,新提交任務將被放入workQueue中,等待線程池中任務調度執行

      當workQueue已滿,且maximumPoolSize>corePoolSize時,新提交任務會創建新線程執行任務

      當提交任務數超過maximumPoolSize時,新提交任務由RejectedExecutionHandler處理

      當線程池中超過corePoolSize線程,空閑時間達到keepAliveTime時,釋放空閑線程

      當設置allowCoreThreadTimeOut(true)時,該參數默認false,線程池中corePoolSize線程空閑時間達到keepAliveTime也將關閉

      Java 任務調度 多線程

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:解決win10 excel打開死機的方法
      下一篇:Spring Security最難的地方就是這個了
      相關文章
      亚洲av成人无码网站…| 伊人久久五月丁香综合中文亚洲| 亚洲乱码无人区卡1卡2卡3| 亚洲国产激情在线一区| 亚洲成人福利在线| 亚洲国产综合专区电影在线| 亚洲香蕉网久久综合影视| 亚洲精品夜夜夜妓女网| 亚洲日韩国产精品第一页一区 | 亚洲人妻av伦理| 亚洲色图综合在线| 久久亚洲av无码精品浪潮| 国产成人亚洲精品狼色在线| 国产亚洲一区二区手机在线观看| 亚洲精品美女久久久久99| 亚洲av永久无码精品国产精品| 亚洲成AV人片在线播放无码| 久久精品国产96精品亚洲| 亚洲情a成黄在线观看动漫尤物| 色婷婷亚洲十月十月色天| 亚洲欧洲日韩综合| 亚洲大成色www永久网址| 中文字幕在线观看亚洲视频| 亚洲欧美第一成人网站7777| 国产精品亚洲av色欲三区| 亚洲国产成人a精品不卡在线| 国产精品亚洲二区在线观看 | 亚洲六月丁香六月婷婷色伊人| 亚洲a视频在线观看| 亚洲乱码av中文一区二区| 大胆亚洲人体视频| 亚洲宅男天堂在线观看无病毒| 亚洲成A人片777777| 亚洲视频一区在线观看| 亚洲伦理一二三四| 亚洲国产成人综合精品| 亚洲天堂在线视频| 无码乱人伦一区二区亚洲| 亚洲国产日韩在线| 亚洲高清一区二区三区电影| 亚洲综合色区在线观看|