30天學Java第九天——線程

并行與并發的區別

  • 并行是多核 CPU 上的多任務處理,多個任務在同一時間真正的同時執行
  • 并發是單核 CPU 上的多任務處理,多個任務在同一時間段內交替執行,通過時間片輪轉實現交替執行,用于解決 IO 密集型任務的瓶頸

線程的創建方式

Thread 的構造方法,可以在創建線程的時候為線程起名字
在這里插入圖片描述

  1. 第一種方法:繼承 Thread 類
    • 第一步:編寫一個類繼承 Thread
    • 第二步:重寫 run 方法
    • 第三步:new 線程對象
    • 第四步:調用線程對象的 start 方法,啟動線程
      一定調用的是 start 方法,不是 run 方法。start 方法的作用就是啟動一個線程,線程啟動完成該方法就結束。
public class MyThread {public static void main(String[] args) {NewThread nt = new NewThread();// 啟動 start 方法啟動線程,而不是 run 方法nt.start();for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + " " + i);}}
}class NewThread extends Thread{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + " " + i);}}
}
對比一下 run 方法與 start 方法的內存圖

調用 run 方法的內存圖
調用 run 方法并沒有啟動新線程,代碼都是在 main 方法中執行的,內存只有一個主線程的棧,因此必須 run 方法中的代碼執行玩,才能執行后續的代碼
在這里插入圖片描述
調用 start 方法的內存圖
調用 start 方法會啟動一個新線程,內存會分配一個新的棧空間給新線程(分配完成start方法就結束了,main 方法中的代碼繼續向下執行),新線程的代碼在新的棧空間執行,main 方法的代碼在 main 方法的棧空間執行,兩個線程搶奪 CPU 時間片交替執行。
在這里插入圖片描述
2. 第二種方法:實現 Runnable 接口

  • 第一步:編寫一個類實現 Runnable 接口
  • 第二步:實現接口中的 run 方法
  • 第三步:new 線程對象
    使用Thread的帶有 Runnable 參數的構造方法創建對象
    在這里插入圖片描述
  • 第四步:調用線程對象的 start 方法,啟動線程

推薦使用這種而不是第一種,因為第一種方式使用繼承,而Java只能單繼承,因此失去了繼承其他類的能力,而 實現 Runnable 接口則還能繼承其他類

  1. 實現 Callable 接口
  • 第一步:編寫一個類實現 Callable 接口
  • 第二步:實現接口中的 run 方法
  • 第三步:new 線程對象
  • 第四步:調用線程對象的 start 方法,啟動線程

線程常用的三個方法

  1. final String getName():返回此線程的名稱。
  2. final void setName(String name):將此線程的名稱更改為等于參數 name 。
  3. static Thread currentThread():返回對當前正在執行的線程對象的引用。

線程七個生命周期

  1. NEW:新建狀態
    當線程被創建但尚未開始運行時,它處于新建狀態。在這個階段,線程對象被實例化,但尚未調用 start() 方法。
  2. RUNNABLE:可運行狀態
    • 就緒狀態
      一旦調用了 start() 方法,線程進入就緒狀態。在這個狀態下,線程準備好運行,并等待線程調度程序的分配。此狀態并不一定代表線程正在運行,可能會處于等待獲取CPU時間片的狀態。
    • 運行狀態
      線程獲得CPU資源并開始執行其任務時,線程進入運行狀態。在這個狀態下,線程執行其代碼。
  3. BLOCKED:阻塞狀態
    當線程嘗試獲取一個已經被其他線程持有的鎖時,它會進入阻塞狀態。在這個狀態下,線程無法繼續執行,直到它獲得所需的鎖。
  4. WAITING:等待狀態
    如果線程調用 wait()、join() 或 LockSupport.park() 方法,它會進入等待狀態。在這種狀態下,線程會等待其他線程通知或喚醒它。
  5. TIMED_WAITING:超時等待狀態
    線程在等待的同時設置了時間限制(例如,調用 sleep(milliseconds) 或 wait(milliseconds)),將進入超時等待狀態。如果在超時時間到達之前線程未被喚醒,則該線程會返回到就緒狀態。
  6. TERMINATED:終止/死亡狀態
    當線程的 run() 方法執行完畢或者因異常終止時,線程進入終止狀態。在這個狀態下,線程完成了它的生命周期,無法重新啟動。

線程常用的調度方法

  1. start()
    用于啟動線程,使其進入就緒狀態。
  2. sleep(long millis)
    使當前正在執行的線程暫停指定的時間,被調用的線程會進入阻塞狀態,在指定的毫秒數后,線程會回到就緒狀態。
  3. yield()
    暫時讓出當前線程的執行權,該方法提示線程調度器允許其他同等優先級的線程獲得執行時間。
    并不保證在調用后立即釋放控制權。
    讓位后的線程進入就緒狀態,并不會阻塞。
  4. join()
    等待一個線程完成,如果線程 A 調用線程 B 的 join() 方法,線程 A 會阻塞,直到線程 B 執行完畢并終止。
    join(long millis) 方法也可以指定時間,指的是加入 A 線程的時間或者說阻塞 A 線程的時間,時間一到就退出。如果在指定的 millis 時間內,B 線程結束了,被阻塞的 A 線程也會結束阻塞狀態。
  5. interrupt()
    發送一個中斷信號給線程。如果線程正處于等待、睡眠或阻塞狀態,將會拋出InterruptedException。拋出異常就會導致線程退出等待、睡眠或阻塞狀態,從而達到中斷的目的,利用了異常的機制。
  6. setPriority(int newPriority)
    設置線程的優先級。線程的優先級是一個整數值,范圍從1(最低)到10(最高)。這并不保證線程會按優先級執行,但可以指示調度器的優先級。
  7. wait() 和 notify()
    用于線程間的通信和協作。wait() 使線程在對象監視器上等待,直到其他線程調用 notify() 或 notifyAll() 來喚醒它。

如何強制結束一個線程

Thread.stop() 方法可以強制結束線程,但是在 Java1.2 之后就被棄用了,因為使用 stop() 方法會導致線程立即終止,這可能導致鎖未解鎖、文件未正確關閉等情況,因此強烈不推薦。更好的辦法是使用標志位或者 interrupt() 方法。

  1. 設置標志位方法
    通過使用一個共享的標志位來控制線程的生命周期是推薦的做法。主線程可以通過設置標志位來通知子線程應停止執行。
    class CustomThread extends Thread {  private volatile boolean running = true; // 使用 volatile 關鍵字確保可見性  public void run() {  while (running) {  // 執行任務  System.out.println("Thread is running...");  try {  Thread.sleep(500); // 模擬工作  } catch (InterruptedException e) {  Thread.currentThread().interrupt(); // 恢復中斷狀態  }  }  System.out.println("Thread is stopping...");  }  public void stopRunning() {  running = false; // 設置標志位  }  
    }  public class Main {  public static void main(String[] args) throws InterruptedException {  CustomThread thread = new CustomThread();  thread.start();  Thread.sleep(2000); // 讓線程運行2秒  thread.stopRunning(); // 請求線程停止  thread.join(); // 等待線程結束  System.out.println("Main thread finished.");  }  
    }
    
  2. 使用 interrupt() 方法
    在Java中,interrupt() 方法可以用于中斷一個線程。線程在被中斷時可以選擇捕捉異常或者檢查中斷狀態,從而優雅地結束自己。
    class InterruptibleThread extends Thread {  public void run() {  try {  while (!Thread.currentThread().isInterrupted()) {  // 執行任務  System.out.println("Thread is running...");  Thread.sleep(500); // 模擬工作  }  } catch (InterruptedException e) {  // 捕捉到中斷異常,線程可以選擇停止  System.out.println("Thread was interrupted.");  Thread.currentThread().interrupt(); // 重新設置中斷狀態  }  System.out.println("Thread is stopping...");  }  
    }  public class Main {  public static void main(String[] args) throws InterruptedException {  InterruptibleThread thread = new InterruptibleThread();  thread.start();  Thread.sleep(2000); // 讓線程運行2秒  thread.interrupt(); // 中斷線程  thread.join(); // 等待線程結束  System.out.println("Main thread finished.");  }  
    }
    

守護線程

在 Java 中,線程被分為兩大類,一類是用戶線程,一類是守護線程。
在 JVM 中,有一個隱藏的守護線程就是 GC 線程

守護線程的特點:

  • 后臺運行: 守護線程通常是后臺執行的,用于執行一些輔助任務,比如垃圾回收、線程池中的工作線程等。
  • 生命周期受限: JVM 會在所有非守護線程結束后自動結束守護線程。如果沒有非守護線程在運行,JVM會退出。
  • 優先級: 守護線程的優先級與普通線程相同,但它們的作用通常是協助非守護線程。

如何創建守護線程

三個步驟創建守護線程:

  1. 創建一個線程實例
  2. 調用 setDaemon(true) 方法,將該線程設置為守護線程
  3. 啟動線程
class DaemonThread extends Thread {  @Override  public void run() {  while (true) {  System.out.println("Daemon thread is running...");  try {  Thread.sleep(1000); // 模擬一些工作  } catch (InterruptedException e) {  System.out.println("Daemon thread interrupted.");  }  }  }  
}  public class Main {  public static void main(String[] args) {  Thread daemonThread = new DaemonThread();  daemonThread.setDaemon(true); // 設置為守護線程  daemonThread.start();  try {  Thread.sleep(3000); // 主線程睡眠3秒  } catch (InterruptedException e) {  e.printStackTrace();  }  System.out.println("Main thread is ending...");  // 主線程結束,Daemon線程會隨之結束  }  
}

定時任務

在Java中,Timer 是一個用于調度任務的工具類,允許開發者在指定的時間間隔內重復執行任務或在特定的時間點執行任務。Timer 類通常與 TimerTask 類一起使用,其功能足夠簡單,適合于許多基本的定時任務需求。
Timer: 一個定時器,負責調度任務。
在這里插入圖片描述
TimerTask: 一個抽象類,所有需要被調度的任務都需要繼承這個類并重寫 run() 方法。
在這里插入圖片描述

創建定時任務

使用 Timer 和 TimerTask 來創建定時任務的基本步驟如下:

  1. 創建一個 Timer 實例。
  2. 創建一個繼承自 TimerTask 的類,并實現 run() 方法。
  3. 使用 Timer 的 schedule() 或 scheduleAtFixedRate() 方法將任務和執行時間關聯。

常用方法

  • schedule(TimerTask task, long delay): 在指定的延遲后調度任務。
  • schedule(TimerTask task, Date time): 在指定的時間執行任務。
  • schedule(TimerTask task, long delay, long period): 設定任務在指定的延遲后每隔一個時間段再次執行。
  • scheduleAtFixedRate(TimerTask task, long delay, long period): 類似于 schedule,但是以固定率運行,適用于需要固定間隔執行的任務。
import java.util.Timer;  
import java.util.TimerTask;  public class TimerExample {  public static void main(String[] args) {  Timer timer = new Timer(); // 創建定時器  TimerTask task = new TimerTask() {  @Override  public void run() {  System.out.println("Task executed at: " + System.currentTimeMillis());  }  };  // 在延遲 1 秒后執行任務,每隔 2 秒重復執行  timer.scheduleAtFixedRate(task, 1000, 2000);  // 主線程睡眠 10 秒,以便觀察輸出  try {  Thread.sleep(10000);  } catch (InterruptedException e) {  e.printStackTrace();  }  // 取消定時器  timer.cancel();  System.out.println("Timer canceled.");  }  
}

注意事項

  • 單線程中: Timer 是單線程的,如果一個 TimerTask 執行時間超過下一個任務的調度時間,后續的任務會被延遲執行。
  • 異常處理: 如果 TimerTask 中的代碼拋出未處理的異常,Timer 將停止執行所有后續任務。應確保 run() 方法內的代碼是異常安全的。
  • 使用 ScheduledExecutorService: 對于更復雜的定時任務需求(例如線程池,多線程調度等),建議使用 ScheduledExecutorService,它提供了更強大的功能和靈活性。
    import java.util.concurrent.*;  public class ScheduledExecutorExample {  public static void main(String[] args) {  ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);  Runnable task = () -> {  System.out.println("Task executed at: " + System.currentTimeMillis());  };  // 在延遲 1 秒后執行,每隔 2 秒重復執行  scheduler.scheduleAtFixedRate(task, 1, 2, TimeUnit.SECONDS);  // 主線程睡眠 10 秒,以便觀察輸出  try {  Thread.sleep(10000);  } catch (InterruptedException e) {  e.printStackTrace();  }  // 關閉調度器  scheduler.shutdown();  System.out.println("Scheduler shut down.");  }  
    }
    
  • 開發中一般不使用 Timer ,有一些更好的框架可以設置定時任務。

線程優先級

  • 線程是可以設置優先級的,優先級高的,獲得CPU時間片的概率會高一些
  • JVM 采用的是搶占式調度模式。誰的優先級高,獲取 CPU 的概率就會高
  • 默認情況下,一個線程的優先級是 5
  • 線程優先級最低是 1,最高是 10
  • Thread 類的字段屬性
    可以通過 MAX_PRIORITY 和 MIN_PRIORITY,設置最高最低優先級
    在這里插入圖片描述

線程安全

什么情況下需要考慮線程安全問題?

  1. 多線程的并發環境下
  2. 有共享的數據
  3. 共享數據涉及到修改操作

一般情況下,局部變量不存在線程安全問題,實例變量和靜態變量可能存在線程安全問題。因為局部遍歷存儲在棧中,實例變量和靜態變量存儲在堆中,棧每個線程使用自己的,而堆是多線程共享的。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/75370.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/75370.shtml
英文地址,請注明出處:http://en.pswp.cn/web/75370.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

論壇系統(測試報告)

文章目錄 一、項目介紹二、設計測試用例三、自動化測試用例的部分展示用戶名或密碼錯誤登錄成功編輯自己的帖子成功修改個人信息成功回復帖子信息成功 四、性能測試總結 一、項目介紹 本平臺是用Java開發&#xff0c;基于SpringBoot、SpringMVC、MyBatis框架搭建的小型論壇系統…

智膳優選 | AI賦能的智慧食堂管理專家 —— 基于飛書多維表格和扣子(Coze)的智能解決方案

智膳優選 | AI賦能的智慧食堂管理專家 基于飛書多維表格和扣子&#xff08;Coze&#xff09;的智能解決方案 數據驅動餐飲管理&#xff0c;讓每一餐都是營養與經濟的完美平衡&#xff01; “智膳優選”通過整合飛書與Coze&#xff0c;將數據智能引入校園餐飲管理&#xff0…

練習(含指針數組與數組指針的學習)

數組指針是一個指向數組的指針&#xff0c;而指針數組是一個存儲指針的數組。 ?數組指針?&#xff1a;是一個指針&#xff0c;指向一個數組的首地址&#xff0c;它用于指向整個數組&#xff0c;而不是數組中的某個元素。例如&#xff0c;int (*p)表示 p 是一個指向包含 5 個整…

NSS#Round30 Web

小桃的PHP挑戰 <?php include jeer.php; highlight_file(__FILE__); error_reporting(0); $A 0; $B 0; $C 0;//第一關 if (isset($_GET[one])){$str $_GET[str] ?? 0;$add substr($str, 0, 1); $add;if (strlen($add) > 1 ) {$A 1;} else {echo $one; } } else…

MCP基礎學習二:MCP服務搭建與配置

文章目錄 MCP服務搭建與配置一&#xff0c;學習目標&#xff1a;二&#xff0c;學習內容&#xff1a;1. 如何搭建MCP服務端服務端初始化與配置MCP服務架構與數據流交互圖核心實現注冊服務功能服務器啟動與API暴露 2. 本地應用與MCP服務的集成客戶端SDK實現客戶端應用實現功能演…

ZKmall開源商城服務端驗證:Jakarta Validation 詳解

ZKmall開源商城基于Spring Boot 3構建&#xff0c;其服務端數據驗證采用Jakarta Validation API?&#xff08;原JSR 380規范&#xff09;&#xff0c;通過聲明式注解與自定義擴展機制實現高效、靈活的數據校驗體系。以下從技術實現、核心能力、場景優化三個維度展開解析&#…

使用Docker創建postgres

準備工作&#xff1a; 1. 檢查網絡 檢查網絡連接&#xff1a;確保你的服務器網絡連接正常&#xff0c;可嘗試使用 ping 命令測試與 Docker Hub 服務器&#xff08;如 ping registry-1.docker.io&#xff09;的連通性。 ping registry-1.docker.io 檢查防火墻&#xff1a;確…

32 python json

在辦公室忙碌的日常里,我們經常需要和各種數據打交道。想象一下,你是辦公室里負責處理員工信息、項目數據的 “數據小管家”,每天都要面對大量格式各異的數據。 這時候,JSON(JavaScript Object Notation)就像是你得力的數據助手,它是一種輕量級的數據交換格式,簡單又高…

Java 實現 List<String> 與 String 互轉

在 Java 開發過程中&#xff0c;有時需要將 List<String> 轉為 String 存儲&#xff0c;后續使用時再還原回去。此時就需要 Java 實現 List<String> 與 String 互轉。以下是一種互轉方式。 采用如下工具包實現。 <dependency><groupId>org.apache.com…

NO.87十六屆藍橋杯備戰|動態規劃-完全背包|瘋狂的采藥|Buying Hay|紀念品(C++)

完全背包 先解決第?問 狀態表?&#xff1a; dp[i][j]表?&#xff1a;從前i個物品中挑選&#xff0c;總體積不超過j&#xff0c;所有的選法中&#xff0c;能挑選出來的最?價 值。&#xff08;這?是和01背包?樣噠&#xff09; 那我們的最終結果就是dp[n][V] 。狀態轉移?…

第十三天 - Ansible基礎架構 - YAML語法與Playbook - 練習:批量配置部署

Ansible自動化運維實戰&#xff1a;從入門到批量配置部署 前言&#xff1a;自動化運維的時代選擇 在服務器規模呈指數級增長的今天&#xff0c;手工操作已無法滿足運維需求。本文將手把手教你使用Ansible這個明星級自動化工具&#xff0c;通過YAML語法和Playbook實現批量配置…

Redis的過期和內存淘汰策略

文章目錄 惰性刪除定期刪除內存滿了&#xff0c;數據淘汰策略 Redis 提供了兩種刪除策略&#xff1a; 惰性刪除 、定期刪除 惰性刪除 定期刪除 兩種清除模式: 內存滿了&#xff0c;數據淘汰策略 Redis 提供了八種數據淘汰策略&#xff1a; 1. 默認是不淘汰任何的 key&#x…

用PHPExcel 封裝的導出方法,支持導出無限列

用PHPExcel 封裝的導出方法&#xff0c;支持導出無限列 避免PHPExcel_Exception Invalid cell coordinate [1 異常錯誤 /*** EXCEL導出* param [string] $file_name 保存的文件名及表格工作區名&#xff0c;不加excel后綴名* param [array] $fields 二維數組* param [array] $…

WHAT - React 元素接收的 ref 詳解

目錄 1. ref 的基本概念2. 如何使用 ref2.1 基本用法2.2 類組件使用 createRef 3. forwardRef 轉發 ref4. ref 的應用場景5. ref 和函數組件總結 在 React 中&#xff0c;ref&#xff08;引用&#xff09;用于訪問 DOM 元素或類組件實例。它允許我們直接與元素進行交互&#xf…

【QT】QT的消息盒子和對話框(自定義對話框)

QT的消息盒子和對話框&#xff08;自定義對話框&#xff09; 一、消息盒子QMessageBox1、彈出警告盒子示例代碼&#xff1a;現象&#xff1a; 2、致命錯誤盒子示例代碼&#xff1a;現象&#xff1a; 3、幫助盒子示例代碼&#xff1a;現象&#xff1a; 4、示例代碼&#xff1a; …

依靠視頻設備軌跡回放平臺EasyCVR構建視頻監控,為幼教連鎖園區安全護航

一、項目背景 幼教行業連鎖化發展態勢越發明顯。在此趨勢下&#xff0c;幼兒園管理者對于深入了解園內日常教學與生活情況的需求愈發緊迫&#xff0c;將這些數據作為提升管理水平、優化教育服務的重要依據。同時&#xff0c;安裝監控系統不僅有效緩解家長對孩子在校安全與生活…

Stable Diffusion+Pyqt5: 實現圖像生成與管理界面(帶保存 + 歷史記錄 + 刪除功能)——我的實驗記錄(結尾附系統效果圖)

目錄 &#x1f9e0; 前言 &#x1f9fe; 我的需求 &#x1f527; 實現過程&#xff08;按功能一步步來&#xff09; &#x1f6b6;?♂? Step 1&#xff1a;基本圖像生成界面 &#x1f5c3;? Step 2&#xff1a;保存圖片并顯示歷史記錄 &#x1f4cf; Step 3&#xff1a…

量子計算未來的潛力和挑戰

據麥肯錫預測&#xff0c;到 2035 年或 2040 年&#xff0c;量子計算市場規模可能增長至約 800 億美元。目前&#xff0c;許多量子比特技術正競相成為首臺通用、無差錯量子計算機的基礎&#xff0c;但仍面臨諸多挑戰。 我們將探討量子計算的未來前景、潛力&#xff0c;以及它對…

ArcGIS 給大面內小面字段賦值

文章目錄 引言:地理數據處理中的自動化賦值為何重要?實現思路模型實現關鍵點效果實現步驟1、準備數據2、執行3、完成4、效果引言:地理數據處理中的自動化賦值為何重要? 在地理信息系統(GIS)的日常工作中,空間數據的屬性字段賦值是高頻且關鍵的操作,例如在土地利用規劃…

如何打通虛擬化-容器環境并保障流量安全?SmartX VCCI 方案升級!

為了提升資源利用率、交付效率和業務靈活性&#xff0c;不少企業用戶都在推進從傳統架構向云原生架構的演進&#xff0c;并采用虛擬機與容器共存的混合模式支持多種業務系統。由于兩個環境在業務交互層面形成高度耦合&#xff0c;企業需要具備簡單、高效方案&#xff0c;實現虛…