java中多線程的一些常見操作

Java 中的多線程是通過并發編程來提高應用程序的效率和響應速度。Java 提供了多個機制和類來支持多線程編程,包括繼承 Thread 類、實現 Runnable 接口、使用線程池等。以下是 Java 中一些常見的多線程操作和應用場景。

1. 創建線程

1.1 通過繼承 Thread 類創建線程

繼承 Thread 類并重寫 run 方法是創建線程的一種方式。run 方法包含線程的執行體。

public class MyThread extends Thread {@Overridepublic void run() {System.out.println("Thread is running: " + Thread.currentThread().getName());}public static void main(String[] args) {MyThread thread = new MyThread();thread.start();  // 啟動線程}
}
  • start() 方法會啟動線程并調用 run() 方法。
  • run() 方法不能直接調用,必須通過 start() 啟動線程。
1.2 通過實現 Runnable 接口創建線程

Runnable 接口適合當你不想繼承 Thread 類時使用。你只需要實現 run 方法,然后將其傳遞給 Thread 對象。

public class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("Thread is running: " + Thread.currentThread().getName());}public static void main(String[] args) {MyRunnable myRunnable = new MyRunnable();Thread thread = new Thread(myRunnable);thread.start();  // 啟動線程}
}

2. 線程的生命周期

線程有幾個常見的生命周期狀態:

  • 新建(New):線程對象被創建,但未調用 start() 方法。
  • 可運行(Runnable):線程被啟動,處于可運行狀態,但可能被操作系統調度暫停。
  • 阻塞(Blocked):線程正在等待某個資源。
  • 等待(Waiting):線程正在等待其他線程執行某些操作。
  • 終止(Terminated):線程執行完畢,生命周期結束。

3. 線程的同步

當多個線程訪問共享資源時,為了避免數據不一致的問題,通常需要使用同步機制。

3.1 使用 synchronized 關鍵字

synchronized 關鍵字用于在方法或代碼塊上加鎖,確保在同一時間內只有一個線程能夠執行被同步的代碼塊。

示例:同步方法
public class Counter {private int count = 0;// 使用 synchronized 修飾方法,保證線程安全public synchronized void increment() {count++;}public int getCount() {return count;}public static void main(String[] args) {Counter counter = new Counter();// 創建兩個線程同時訪問共享資源Thread t1 = new Thread(() -> {for (int i = 0; i < 1000; i++) {counter.increment();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 1000; i++) {counter.increment();}});t1.start();t2.start();try {t1.join();  // 等待線程 t1 執行完畢t2.join();  // 等待線程 t2 執行完畢} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Final count: " + counter.getCount());  // 輸出: Final count: 2000}
}

在上面的例子中,increment 方法被 synchronized 修飾,這意味著同一時刻只有一個線程能夠訪問這個方法。

3.2 使用同步代碼塊

你也可以使用同步代碼塊來鎖定指定的代碼區域,從而減少鎖的范圍,提高效率。

public class Counter {private int count = 0;public void increment() {synchronized (this) {  // 鎖定當前對象count++;}}public int getCount() {return count;}public static void main(String[] args) {Counter counter = new Counter();Thread t1 = new Thread(() -> {for (int i = 0; i < 1000; i++) {counter.increment();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 1000; i++) {counter.increment();}});t1.start();t2.start();try {t1.join();  // 等待線程 t1 執行完畢t2.join();  // 等待線程 t2 執行完畢} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Final count: " + counter.getCount());  // 輸出: Final count: 2000}
}

在上面的代碼中,increment 方法內的同步代碼塊確保了每次只有一個線程能夠進入該代碼塊,防止了競態條件的出現。

4. 線程間通信

線程間通信是在多個線程之間交換信息的機制。Java 提供了 wait()notify()notifyAll() 方法來實現線程間的通信。

4.1 使用 wait()notify() 進行線程通信
  • wait():使當前線程進入等待狀態,并釋放鎖,直到被其他線程通知。
  • notify():通知一個正在等待的線程,使其從等待狀態中醒來,繼續執行。
  • notifyAll():通知所有正在等待的線程,所有線程都會嘗試重新獲取鎖。
示例:生產者-消費者問題
class Storage {private int product = 0;private final int capacity = 10;// 生產者生產產品public synchronized void produce() throws InterruptedException {while (product >= capacity) {wait();  // 如果庫存已滿,生產者等待}product++;System.out.println("Produced, product count: " + product);notifyAll();  // 通知消費者線程}// 消費者消費產品public synchronized void consume() throws InterruptedException {while (product <= 0) {wait();  // 如果庫存為空,消費者等待}product--;System.out.println("Consumed, product count: " + product);notifyAll();  // 通知生產者線程}
}public class ProducerConsumer {public static void main(String[] args) {Storage storage = new Storage();// 生產者線程Thread producer = new Thread(() -> {try {for (int i = 0; i < 20; i++) {storage.produce();Thread.sleep(100);  // 模擬生產時間}} catch (InterruptedException e) {e.printStackTrace();}});// 消費者線程Thread consumer = new Thread(() -> {try {for (int i = 0; i < 20; i++) {storage.consume();Thread.sleep(150);  // 模擬消費時間}} catch (InterruptedException e) {e.printStackTrace();}});producer.start();consumer.start();}
}

在這個例子中,我們模擬了生產者和消費者的線程通信機制。生產者線程不斷生產產品,而消費者線程不斷消費產品。當產品庫存滿時,生產者等待;當產品庫存為空時,消費者等待。

5. 線程池(Executor Service)

線程池是 Java 提供的一個高效的多線程管理工具,它可以避免創建過多的線程,減少系統資源的消耗。Java 中的線程池是通過 ExecutorService 接口來管理的。

5.1 創建線程池

線程池的創建通常使用 Executors 工廠類,它提供了幾種常用的線程池:

  • newFixedThreadPool(int n):創建一個固定大小的線程池。
示例:使用 ExecutorService 執行任務
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPoolExample {public static void main(String[] args) {// 創建一個固定大小的線程池,池中有 3 個線程ExecutorService executorService = Executors.newFixedThreadPool(3);// 提交多個任務給線程池for (int i = 0; i < 5; i++) {executorService.submit(() -> {System.out.println("Task executed by: " + Thread.currentThread().getName());try {Thread.sleep(1000);  // 模擬任務執行} catch (InterruptedException e) {e.printStackTrace();}});}// 關閉線程池executorService.shutdown();  // 提交完任務后調用 shutdown 來關閉線程池}
}

6. 線程的優先級

Java 允許設置線程的優先級,從而影響線程的調度順序。線程的優先級是一個整數值,范圍從 1 到 10,其中 1 為最低優先級,10 為最高優先級。

示例:設置線程優先級
public class ThreadPriority {public static void main(String[] args) {Thread highPriorityThread = new Thread(() -> {System.out.println("High priority thread is running.");});Thread lowPriorityThread = new Thread(() -> {System.out.println("Low priority thread is running.");});highPriorityThread.setPriority(Thread.MAX_PRIORITY);  // 設置高優先級lowPriorityThread.setPriority(Thread.MIN_PRIORITY);  // 設置低優先級highPriorityThread.start();lowPriorityThread.start();}
}

注意,雖然 Java 提供了線程優先級的設置,但線程調度是由操作系統管理的,不同的操作系統可能會根據自己的調度算法來決定線程的實際執行順序。

7. 中斷線程

線程的中斷通常用于停止線程的執行或通知線程需要停止。通過調用線程的 interrupt() 方法可以設置線程的中斷標志,而線程可以通過 isInterrupted() 方法來檢查自己是否被中斷。需要注意的是,interrupt() 并不會立即終止線程,它只是設置線程的中斷狀態,具體的中斷行為需要在線程代碼中自行判斷并處理。

示例:中斷線程
public class InterruptExample {public static void main(String[] args) throws InterruptedException {Thread longRunningThread = new Thread(() -> {try {for (int i = 0; i < 10; i++) {if (Thread.interrupted()) {System.out.println("Thread is interrupted, stopping...");return;  // 響應中斷,終止線程}System.out.println("Running... " + i);Thread.sleep(1000);  // 模擬長時間任務}} catch (InterruptedException e) {System.out.println("Thread was interrupted during sleep.");}});longRunningThread.start();// 等待 3 秒后中斷線程Thread.sleep(3000);longRunningThread.interrupt();  // 發出中斷信號}
}

8. 線程的 join() 方法

join() 方法用于等待一個線程完成。當調用 join() 方法時,當前線程會阻塞,直到目標線程執行完畢為止。它常用于確保某些任務執行完之后再執行其他任務。

示例:使用 join() 等待線程完成
public class JoinExample {public static void main(String[] args) throws InterruptedException {Thread thread1 = new Thread(() -> {try {Thread.sleep(2000);  // 模擬任務執行System.out.println("Thread 1 finished");} catch (InterruptedException e) {e.printStackTrace();}});Thread thread2 = new Thread(() -> {try {Thread.sleep(1000);  // 模擬任務執行System.out.println("Thread 2 finished");} catch (InterruptedException e) {e.printStackTrace();}});thread1.start();thread2.start();// 等待 thread1 和 thread2 完成后再繼續執行thread1.join();thread2.join();System.out.println("All threads finished");}
}

在這個例子中,main 線程會等待 thread1thread2 執行完畢后再繼續執行。

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

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

相關文章

使用 Docker 搭建 Hadoop 集群

1.1. 啟用 WSL 與虛擬機平臺 1.1.1. 啟用功能 啟用 WSL并使用 Moba 連接-CSDN博客 1.2 安裝 Docker Desktop 最新版本鏈接&#xff1a;Docker Desktop: The #1 Containerization Tool for Developers | Docker 指定版本鏈接&#xff1a;Docker Desktop release notes | Do…

【每日學點鴻蒙知識】廣告ID、NFC手機充值、CSS支持語法、PC與模擬器交互、SO熱更新等

1、HamonyOS 樣機獲取成功返回Oaid為00000000-0000-0000-0000-000000000000&#xff1f; 請求授權時需要觸發動態授權彈窗,看一下是不是沒有觸發授權彈窗。 可以參考以下代碼以及文檔&#xff1a; // ets import identifier from ohos.identifier.oaid; import hilog from oh…

【YOLO 項目實戰】(12)紅外/可見光多模態目標檢測

歡迎關注『youcans動手學模型』系列 本專欄內容和資源同步到 GitHub/youcans 【YOLO 項目實戰】&#xff08;10&#xff09;YOLO8 環境配置與推理檢測 【YOLO 項目實戰】&#xff08;11&#xff09;YOLO8 數據集與模型訓練 【YOLO 項目實戰】&#xff08;12&#xff09;紅外/可…

logback日志框架源碼分析

目錄 (一)入口:slf4j選擇日志框架 (二)日志框架初始化 (1)logback的3種配置方式 a、BasicConfigurator默認配置 b、SPI方式配置的Configurator實現類 c、通過配置文件初始化 (2)xml配置文件初始化 (三)Logger的創建 (四)打印日志 本文源碼基于:logback版…

國產數據庫OceanBase從入門到放棄教程

1. 介紹 是由螞蟻集團&#xff08;Ant Group&#xff0c;原螞蟻金服&#xff09;自主研發的分布式關系型數據庫。它旨在解決海量數據存儲和高并發訪問的問題&#xff0c;特別適合金融級應用場景&#xff0c;如支付寶等對數據一致性、可靠性和性能有極高要求的服務。以下是關于…

連接Milvus

連接到Milvus 驗證Milvus服務器正在偵聽哪個本地端口。將容器名稱替換為您自己的名稱。 docker port milvus-standalone 19530/tcp docker port milvus-standalone 2379/tcp docker port milvus-standalone 192.168.1.242:9091/api/v1/health 使用瀏覽器訪問連接地址htt…

機器學習中的欠擬合

當模型不能夠準確地表達輸入與輸出的關系時&#xff0c;就是欠擬合。它在訓練集和未見過的數據都會產生高誤差率。過度擬合則在訓練集表現出低誤差率&#xff0c;只有對未見過的數據表現出高誤差率。 當模型太過于簡單時&#xff0c;它需要更多的訓練時間、更多的輸入特征、更…

安卓入門二 Kotlin基礎

Kotlin Kotlin的歷史 Kotlin由Jet Brains公司開發設計&#xff0c;2011年公布第一版&#xff0c;2012年開源。 2016年發布1.0正式版&#xff0c;并且Jet Brains在IDEA加入對Kotlin的支持&#xff0c;安卓自此又有新的選擇。 2019年谷歌宣布Kotlin成為安卓第一開發語言&#x…

淺談Cocos2djs逆向

前言 簡單聊一下cocos2djs手遊的逆向&#xff0c;有任何相關想法歡迎和我討論^^ 一些概念 列出一些個人認為比較有用的概念&#xff1a; Cocos遊戲的兩大開發工具分別是CocosCreator和CocosStudio&#xff0c;區別是前者是cocos2djs專用的開發工具&#xff0c;後者則是coco…

STM32驅動NRF24L01

一、NRF24L01的相關介紹 1.2 引腳的介紹 關于SPI的引腳就不再說了&#xff0c;這里介紹其余的兩個引腳&#xff1a; CE 模塊控制引腳&#xff1a;芯片開啟信號&#xff0c;激活RX或TX模式 IRQ 模塊中斷信號輸出引腳&#xff1a;其低電平有效&#xff0c;也就是中斷時變為低電平…

【Python】 glob批處理模塊的學習

1.什么是glob模塊&#xff1f; 在 Python 中&#xff0c;glob模塊是一個用于文件路徑名的模式匹配的工具。它使用簡單的通配符規則來匹配文件和目錄的路徑&#xff0c;這些通配符規則類似于在命令行中使用的文件搜索規則。這使得在處理文件系統中的多個文件或目錄時非常方便&am…

Android 系統 AlarmManager 系統層深度定制

Android 系統 AlarmManager 系統層深度定制 目錄 引言AlarmManager 概述AlarmManager 系統架構AlarmManager 核心代碼解讀AlarmManager 深度定制方法 修改 AlarmManagerService 修改定時任務調度策略增加定時任務類型定制內核層 修改定時觸發精度增加定時觸發類型優化定時任務…

解決vue-i18n在非.vue文件中,在其他js文件中無法使用的問題

其實很簡單&#xff0c;把i18n直接掛載到window上&#xff0c;全局可使用。下面請看詳細。 一、安裝 npm install vue-i18n9二、在vue的main.js中引入 import Vue from "vue" import VueI18n from vue-i18n Vue.use(VueI18n)//注入到所有的子組件&#xff0c;就是…

線性代數期末復習 [基礎篇]

關于第六點: AXB 在期末考試中一般A都是可逆的 我們可以先把A的逆求出來,X A ? 1 B A^-1B A?1B,或者 (A,B) -> r (E, A ? 1 B A^-1B A?1B) 如果A矩陣不可逆,轉變為方程組求解問題,假設都是二維矩陣 A(x1,x2) (b1,b2) Ax1 b1,Ax2 b2 XAB 如果A可逆,直接XB A ? 1 A^-…

C++ —— 數據類型轉換和數據類型的別名

數據類型轉換 引言自動類型轉換強制類型轉換數據類型的別名 引言 計算機進行運算時&#xff0c;要求各操作數的數據類型、大小和存儲方式都要相同。&#xff08;例如&#xff1a;8字節的整數和8字節的浮點數&#xff0c;雖然占用內存大小一樣&#xff0c;但是存儲方式不同&…

Kali 自動化換源腳本編寫與使用

1. 背景與需求 在使用 Kali Linux 的過程中&#xff0c;軟件源的配置對系統的更新與軟件安裝速度至關重要。 Kali 的默認官方源提供了安全且最新的軟件包&#xff0c;但有時由于網絡條件或地理位置的限制&#xff0c;使用官方源可能會出現速度較慢的問題。 為了解決這一問題&a…

設計模式-創建型-工廠方法模式

什么是工廠方法模式&#xff1f; 工廠方法模式&#xff08;Factory Method Pattern&#xff09;是 創建型設計模式之一&#xff0c;目的是通過定義一個用于創建對象的接口&#xff0c;讓子類決定實例化哪個類。簡而言之&#xff0c;工廠方法模式通過延遲對象的創建過程到子類來…

【Unity3D】ECS入門學習(十二)IJob、IJobFor、IJobParallelFor

IJob&#xff1a;開啟單個線程進行計算&#xff0c;線程內不允許對同一個數據進行操作&#xff0c;也就是如果你想用多個IJob分別計算&#xff0c;將其結果存儲到同一個NativeArray<int>數組是不允許的&#xff0c;所以不要這樣做&#xff0c;如下例子就是反面教材&#…

Spring 創建和管理 Bean 的原理,以及Spring 的單例模式是否線程安全?(有無狀態Bean)

Spring 是一個輕量級的開源框架&#xff0c;廣泛應用于 Java 企業級應用的開發。它提供了一個全面的、基于 IOC&#xff08;控制反轉&#xff09;和 AOP&#xff08;面向切面編程&#xff09;的容器&#xff0c;可以幫助開發者更好地管理應用程序中的對象。 Spring 創建和管理…

Docker容器鏡像制作

Docker鏡像的基本概念 1. 什么是Docker鏡像&#xff1f; Docker鏡像是一種輕量級、可執行的軟件包&#xff0c;包含運行某個應用所需的所有代碼、庫、依賴項和配置文件。它的形成是一種“打包”和“快照”過程&#xff0c;使得應用能夠在不同環境中保持一致的功能表現。 2. …