Java多線程:從基礎到實戰

引言

多線程是Java并發編程的核心技術之一,廣泛應用于服務器開發、數據處理、實時系統等領域。通過多線程,程序可以充分利用CPU資源,提高執行效率,同時處理多個任務。本文將從多線程的基本概念實現方式線程狀態同步與通信常見問題與解決方案,深入解析Java多線程的原理與實踐。


一、多線程的核心概念

1. 什么是線程?

線程是操作系統能夠進行運算調度的最小單位。一個進程可以包含多個線程,它們共享進程的資源(如內存),但每個線程有獨立的執行路徑。

2. 多線程的優勢

  • 提高程序性能:通過并行執行多個任務,充分利用多核CPU。
  • 異步處理:避免主線程阻塞(如GUI應用、網絡請求)。
  • 資源共享:線程間可直接共享進程的內存數據(需注意線程安全)。

3. 多線程與并發的區別

  • 并發:多個任務交替執行,邏輯上“同時”進行(如單核CPU的多任務調度)。
  • 并行:多個任務真正同時執行(如多核CPU的多線程協作)。

二、Java多線程的實現方式

1. 繼承?Thread?類

class MyThread extends Thread {@Overridepublic void run() {System.out.println("線程執行:" + Thread.currentThread().getName());}
}
// 啟動線程
new MyThread().start();

缺點:Java單繼承限制,無法繼承其他類。

2. 實現?Runnable?接口(推薦)

class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("線程執行:" + Thread.currentThread().getName());}
}
// 啟動線程
new Thread(new MyRunnable()).start();

優點:避免單繼承限制,便于資源共享(如多個線程操作同一實例)。

3. 使用?Callable?接口(帶返回值)

class MyCallable implements Callable<String> {@Overridepublic String call() throws Exception {return "結果:" + Thread.currentThread().getName();}
}
// 提交任務
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(new MyCallable());
System.out.println(future.get());
executor.shutdown();

4. 線程池(推薦)

線程池管理線程復用,避免頻繁創建銷毀線程:

ExecutorService pool = Executors.newFixedThreadPool(5); // 固定大小線程池
pool.execute(() -> System.out.println("任務執行"));
pool.shutdown();

三、線程的生命周期與狀態

Java線程有以下5種基本狀態(JDK 1.8):

狀態說明
新建(New)創建線程對象后,調用?start()?之前的狀態。
就緒(Runnable)調用?start()?后,等待CPU調度執行。
運行(Running)CPU開始調度線程,執行?run()?方法。
阻塞(Blocked)線程因等待鎖、I/O、休眠等原因暫時停止。
終止(Terminated)線程執行完畢或拋出異常退出。

阻塞狀態細分

  1. 等待阻塞:調用?wait(),進入等待池(需?notify()?喚醒)。
  2. 同步阻塞:未獲取到?synchronized?鎖。
  3. 其他阻塞:調用?sleep()join()?或I/O操作。

四、線程同步與線程安全

1. 什么是線程安全?

當多個線程并發訪問共享資源時,程序仍能正確運行(無數據錯誤、狀態混亂)。

2. 常見問題與解決方案

(1)原子性問題
  • 問題:非原子操作(如?count++)被多個線程拆分執行。
  • 解決方案
    • synchronized?關鍵字
      public synchronized void increment() {count++;
      }
    • ReentrantLock?顯式鎖
      ReentrantLock lock = new ReentrantLock();
      public void increment() {lock.lock();try {count++;} finally {lock.unlock();}
      }
    • 原子類(AtomicXXX)
      AtomicInteger atomicCount = new AtomicInteger(0);
      atomicCount.incrementAndGet(); // 線程安全的自增
(2)可見性問題
  • 問題:線程A修改變量后,線程B未及時讀取到最新值。
  • 解決方案
    • volatile?關鍵字
      private volatile boolean flag = false; // 禁止指令重排序,保證可見性
(3)有序性問題
  • 問題:編譯器或CPU優化導致指令順序變化。
  • 解決方案
    • synchronized?/?volatile:通過內存屏障確保順序。

五、線程通信:生產者-消費者模型

經典場景

  • 生產者:每秒生成一個產品,交給店員。
  • 消費者:每秒購買一個產品。
  • 店員:最多管理20個產品。

實現代碼

class Clerk {private int productCount = 0;private static final int MAX_CAPACITY = 20;// 生產產品public synchronized void produce() throws InterruptedException {while (productCount >= MAX_CAPACITY) {System.out.println(Thread.currentThread().getName() + " 庫存已滿,等待...");wait();}productCount++;System.out.println(Thread.currentThread().getName() + " 生產了1個產品,庫存:" + productCount);notifyAll();}// 消費產品public synchronized void consume() throws InterruptedException {while (productCount <= 0) {System.out.println(Thread.currentThread().getName() + " 沒有產品,等待...");wait();}productCount--;System.out.println(Thread.currentThread().getName() + " 購買了1個產品,庫存:" + productCount);notifyAll();}
}// 生產者
class Producer implements Runnable {private Clerk clerk;public Producer(Clerk clerk) { this.clerk = clerk; }@Overridepublic void run() {while (true) {try {clerk.produce();Thread.sleep(1000);} catch (InterruptedException e) {Thread.currentThread().interrupt();break;}}}
}// 消費者
class Customer implements Runnable {private Clerk clerk;public Customer(Clerk clerk) { this.clerk = clerk; }@Overridepublic void run() {while (true) {try {clerk.consume();Thread.sleep(1000);} catch (InterruptedException e) {Thread.currentThread().interrupt();break;}}}
}

六、多線程避坑指南

1. 死鎖問題

死鎖條件

  • 互斥:資源不可共享。
  • 請求與保持:線程持有資源并申請新資源。
  • 不可剝奪:資源只能由持有線程釋放。
  • 循環等待:多個線程形成資源環。

解決方案

  • 按固定順序加鎖:避免循環等待。
  • 超時機制:使用?tryLock()?設置超時時間。
  • 資源監控:通過?jstack?分析死鎖。

2. 線程池使用不當

錯誤示例

void realJob() {ThreadPoolExecutor exe = new ThreadPoolExecutor(...); // 每次請求新建線程池exe.submit(new Runnable() {...});
}

后果:線程池爆炸,耗盡系統資源。

正確做法

  • 將線程池作為靜態變量復用。
  • 使用?Executors?工廠方法(如?newFixedThreadPool)。

七、總結

Java多線程是提升程序性能的關鍵技術,但也伴隨著復雜的并發問題。掌握以下核心要點:

  1. 線程創建與啟動:優先使用?Runnable?和線程池。
  2. 線程同步synchronizedReentrantLock、原子類。
  3. 線程通信wait()/notify()?實現生產者-消費者模型。
  4. 避免死鎖:按順序加鎖、超時機制。
  5. 線程池管理:避免資源耗盡,復用線程。

通過合理設計和實踐,多線程可以成為構建高性能、高可靠系統的重要工具。

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

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

相關文章

list集合可以一邊遍歷一遍修改元素嗎?

今天看來一下Java中list集合部分的八股&#xff0c;發現了一個以前沒注意過的問題&#xff0c;記錄一下list可以一邊遍歷一邊修改元素嗎&#xff1f;答&#xff1a;在 Java 中&#xff0c;List在遍歷過程中是否可以修改元素取決于遍歷方式和具體的List實現類。①&#xff1a;對…

Infusing fine-grained visual knowledge to Vision-Language Models

Infusing fine-grained visual knowledge to Vision-Language Models Authors: Nikolaos-Antonios Ypsilantis, Kaifeng Chen, Andr Araujo, Ond?ej Chum Deep-Dive Summary: 視覺-語言模型中注入細粒度視覺知識 摘要 大規模對比預訓練產生了強大的視覺-語言模型&#xf…

RK3576賦能無人機巡檢:多路視頻+AI識別引領智能化變革

隨著工業巡檢任務的復雜度不斷提升&#xff0c;無人機逐漸取代傳統人工&#xff0c;成為電力、能源、林業、農業等行業的“高空作業主力”。然而&#xff0c;巡檢并非簡單的拍攝和回放&#xff0c;它要求無人機實時采集多路畫面、快速分析異常&#xff0c;并穩定回傳數據。這對…

ollama Modelfile 文件生成

輸入 根據如下TEMPLATE和params寫一個modelfile文件&#xff0c;TEMPLATE為&#xff1a;{{- $lastUserIdx : -1 -}} {{- range $idx, $msg : .Messages -}} {{- if eq $msg.Role “user” }}{{ $lastUserIdx $idx }}{{ end -}} {{- end }} {{- if or .System .Tools }}<|i…

關聯規則挖掘2:FP-growth算法(Frequent Pattern Growth,頻繁模式增長)

目錄 一、核心思想&#xff1a;一個形象的比喻 二、核心思想的具體拆解 步驟一&#xff1a;構建FP-tree&#xff08;頻繁模式樹&#xff09; 步驟二&#xff1a;從FP-tree中挖掘頻繁項集 為什么這很高效&#xff1f; 三、總結 核心思想與優勢 適用場景與缺點 四、例題…

在IDEA中DEBUG調試時查看MyBatis-Plus動態生成的SQL語句

在IDEA中DEBUG調試時查看MyBatis-Plus動態生成的SQL語句前言&#xff1a;動態SQL調試的痛與解決方案一、準備工作&#xff1a;調試前的檢查清單二、基礎方法&#xff1a;SqlSessionTemplate斷點調試步驟1&#xff1a;定位SqlSessionTemplate類步驟2&#xff1a;在invoke方法上設…

Linux 文本處理三劍客:awk、grep、sed 完全指南

Linux 文本處理三劍客&#xff1a;awk、grep、sed 完全指南 1. 概述 Linux 系統提供了三個強大的文本處理工具&#xff1a;awk、grep 和 sed&#xff0c;它們各有所長&#xff0c;結合使用可以高效地處理文本數據。 awk&#xff1a;擅長文本分析和格式化輸出&#xff0c;是一…

pyecharts可視化圖表組合組件_Grid:打造專業數據儀表盤

pyecharts可視化圖表組合組件_Grid&#xff1a;打造專業數據儀表盤 目錄pyecharts可視化圖表組合組件_Grid&#xff1a;打造專業數據儀表盤引言圖表1&#xff1a;Grid-Overlap-多X/Y軸示例代碼解析1. 圖表創建2. 多軸配置3. 圖表重疊4. Grid布局效果與應用圖表2&#xff1a;Gri…

【電氣工程學習】

三極管中&#xff1a;集電極C,基極B&#xff0c;發射極E接線&#xff1a;棕正藍負黑信號NPN開關輸出的是我們的0V,也叫低電平PNP開關輸出的是24V,也就是高電平&#xff08;NPN開關導通時&#xff0c;相當于把輸出端“拉”到0V&#xff08;低電平&#xff09;&#xff0c;稱為“…

【嵌入式】CAN通信

CAN 總線最初由博世于1980年代為汽車行業開發&#xff0c;能夠簡化復雜的布線網絡&#xff0c;還確保可靠和安全的數據傳輸。 1.CAN技術解釋 CAN網絡中的每個節點&#xff0c;都是平等的&#xff0c;沒有主次之分&#xff0c;這一點和SPI和I2C不同。每個節點都可以在需要的時…

Apache ShenYu網關與Nacos的關聯及如何配合使用

Apache ShenYu 網關與 Nacos 之間的關系可以概括為 “協作互補”:Nacos 作為 服務注冊與配置中心,為 ShenYu 提供動態的服務發現和配置管理能力,而 ShenYu 作為 流量網關,依賴 Nacos 實現路由信息的動態更新和實時生效。以下是詳細解析: 1. 核心關系圖解 拉取服務列表/路…

【CPP】一個CPP的Library(libXXXcore)和測試程序XXX_main的Demo

一個CPP的Library和測試程序Demo 1. 思路描述 目錄結構 總控CMakeList.txt文件 2. Library代碼實現 2.1 XXXLib.hpp文件(對外的接口定義文件)和XXXLib.cpp文件 2.1.1 XXXLib.hpp文件 2.1.2 XXXLib.cpp文件 2.2 CXXXLibApi.hpp文件和CXXXLibApi.cpp文件(內部的API基類) 2.2.1 CX…

【YashanDB認證】學習YashanDB的探索之路:從入門到實踐

在國產數據庫蓬勃發展的浪潮中&#xff0c;選擇了YashanDB作為技術學習的切入點。這不僅讓我深入了解了數據庫的核心技術&#xff0c;也讓我深刻體會到國產數據庫在性能、可靠性和生態適配上的創新價值。以下是我在學習YashanDB過程中的經驗與感悟。 一、YashanDB基礎介紹 Ya…

element UI 和 element plus 在組件上有哪些不同

Element UI 和 Element Plus 都是基于 Vue 的桌面端 UI 組件庫&#xff0c;由同一團隊&#xff08;餓了么前端團隊&#xff09;開發和維護。Element Plus 是 Element UI 的升級版&#xff0c;專為 Vue 3 設計&#xff0c;而 Element UI 僅支持 Vue 2。以下是它們在組件層面的主…

【3D重建技術】如何基于遙感圖像和DEM等數據進行城市級高精度三維重建?

城市級高精度三維重建是融合多源空間數據&#xff08;遙感圖像、DEM、GIS矢量等&#xff09;、計算機視覺與地理信息處理技術的復雜過程&#xff0c;核心目標是構建包含“地形地物&#xff08;建筑、道路、植被等&#xff09;”的真實、高精度三維場景。其流程可分為數據準備、…

【unitrix數間混合計算】3.4 無符號小數部分標記trait(bin_unsigned.rs)

一、源碼 這段代碼定義了一個類型級二進制小數系統&#xff0c;用于在編譯時表示和驗證二進制小數部分的有效性。 use crate::number::{F0, BFrac, Bit};/// 標記合法的二進制小數部分類型 pub trait BinFrac: Copy Default static {}// 空小數部分&#xff08;表示值為0&…

從一次 DDoS 的“死亡回放”看現代攻擊鏈的進化

本文記錄的是作者上周在測試環境真實踩到的坑。為了讓讀者能復現并親手體驗防御思路&#xff0c;文末給出了一份最小可運行的 Go 腳本&#xff0c;支持本地壓測 日志回放&#xff0c;方便對比加防護前后的差異。攻擊現場還原 周一凌晨 2:14&#xff0c;監控群里突然彈出告警&a…

LeetCode熱題100--101. 對稱二叉樹--簡單

1. 題目 給你一個二叉樹的根節點 root &#xff0c; 檢查它是否軸對稱。 示例 1&#xff1a;輸入&#xff1a;root [1,2,2,3,4,4,3] 輸出&#xff1a;true 示例 2&#xff1a;輸入&#xff1a;root [1,2,2,null,3,null,3] 輸出&#xff1a;false 2. 題解 /*** Definition for…

Pub/Sub是什么意思

Pub/Sub&#xff08;發布/訂閱模式&#xff09;?? 是一種異步消息通信范式&#xff0c;用于分布式系統中不同組件之間的解耦通信。它的核心思想是將消息的發送方&#xff08;發布者&#xff09;?? 和接收方&#xff08;訂閱者&#xff09;?? 分離&#xff0c;通過一個中間…

Redisson3.14.1及之后連接阿里云redis代理模式,使用分布式鎖:ERR unknown command ‘WAIT‘

文章目錄一、問題背景1、問題原因2、阿里云對Redisson的支持二、解決方案1、繼續使用Redisson3.14.0版本2、阿里云redis改為直連模式3、升級Redisson版本到 3.47.0一、問題背景 1、問題原因 阿里云Redis分直連和代理模式&#xff0c;其中代理模式是不支持WAIT命令的。 目前嘗…