Java使用線程實現異步運行

在Java中,實現異步運行的一個常用方式是使用Thread類。下面,我將給出一個詳細且完整的示例,該示例將創建一個簡單的異步任務,該任務將模擬一個耗時的操作(比如,模擬網絡請求或文件處理)。

1. 使用Thread類實現異步運行

假設我們有一個任務,該任務需要模擬一個耗時操作,比如從網絡下載一個大文件。我們將使用Thread類來異步執行這個任務,以便主程序可以繼續執行其他任務,而不需要等待下載完成。

public class AsyncTaskExample {  // 模擬耗時任務的Runnable實現  static class LongRunningTask implements Runnable {  @Override  public void run() {  // 模擬耗時操作,例如網絡請求或文件處理  try {  // 使用Thread.sleep來模擬耗時操作  System.out.println("開始執行耗時任務...");  Thread.sleep(5000); // 假設這個任務是耗時5秒的  System.out.println("耗時任務完成!");  } catch (InterruptedException e) {  Thread.currentThread().interrupt(); // 保持中斷狀態  System.out.println("任務被中斷!");  }  }  }  public static void main(String[] args) {  // 創建Runnable實例  Runnable task = new LongRunningTask();  // 創建Thread實例,并將Runnable作為任務傳遞  Thread thread = new Thread(task);  // 啟動線程  System.out.println("啟動異步任務...");  long startTime = System.currentTimeMillis(); // 記錄開始時間  thread.start(); // 啟動線程,注意start()方法調用后,線程將獨立執行  // 主線程繼續執行,不等待異步任務完成  for (int i = 0; i < 5; i++) {  System.out.println("主線程正在執行其他任務... " + i);  try {  Thread.sleep(1000); // 模擬主線程正在執行其他任務  } catch (InterruptedException e) {  Thread.currentThread().interrupt();  }  }  long endTime = System.currentTimeMillis(); // 記錄結束時間  System.out.println("主線程結束,耗時:" + (endTime - startTime) + "毫秒");  // 注意:這里的代碼不會等待異步線程完成,如果我們需要等待異步線程完成,可以調用thread.join();  // 但是在這個例子中,我們不會這樣做,以展示異步執行的特性  }  
}

代碼解釋:

(1)LongRunningTask:這是一個實現了Runnable接口的類,用于封裝耗時的任務。在這個例子中,我們使用Thread.sleep(5000)來模擬耗時操作。

(2)main方法

  • 創建一個LongRunningTask的實例。

  • 使用這個實例作為參數創建一個Thread對象。

  • 調用thread.start()來啟動線程,這將導致LongRunningTaskrun方法在新線程中異步執行。

  • 在主線程中,我們使用一個循環來模擬主線程正在執行的其他任務,并使用Thread.sleep(1000)來模擬這些任務的耗時。

  • 注意到主線程不會等待異步線程完成,它將繼續執行直到循環結束。

注意事項:

  • 異步執行意味著主線程和異步線程將并行執行,互不干擾。

  • 如果需要主線程等待異步線程完成,可以調用thread.join()。但在上面的示例中,我們沒有這樣做以展示異步執行的特性。

  • 在處理多線程時,要特別注意線程安全和資源同步問題。上面的示例較為簡單,沒有涉及到這些高級概念。但在實際應用中,這些問題可能非常重要。

除了直接使用Thread類之外,Java還提供了其他幾種實現異步運行的方法。以下是一些常用的方法,并給出詳細的代碼示例。

2. 使用ExecutorService

ExecutorServicejava.util.concurrent包中的一個接口,它提供了一種更靈活的方式來管理線程池中的線程。使用ExecutorService可以方便地控制線程的數量、執行異步任務,并獲取任務執行的結果。

import java.util.concurrent.Callable;  
import java.util.concurrent.ExecutionException;  
import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
import java.util.concurrent.Future;  public class ExecutorServiceExample {  // 模擬耗時任務的Callable實現  static class LongRunningTask implements Callable<String> {  @Override  public String call() throws Exception {  // 模擬耗時操作  Thread.sleep(5000);  return "任務完成";  }  }  public static void main(String[] args) {  // 創建一個固定大小的線程池  ExecutorService executor = Executors.newFixedThreadPool(2);  // 提交任務并獲取Future對象  Future<String> future = executor.submit(new LongRunningTask());  // 主線程繼續執行其他任務  System.out.println("主線程正在執行其他任務...");  try {  // 如果需要,可以等待異步任務完成并獲取結果  String result = future.get(); // 這將會阻塞,直到任務完成  System.out.println("異步任務結果: " + result);  } catch (InterruptedException | ExecutionException e) {  e.printStackTrace();  }  // 關閉線程池(注意:這不會立即停止正在執行的任務)  executor.shutdown();  // 如果我們想立即停止所有正在執行的任務,可以使用shutdownNow(),但這通常不是推薦的做法  // executor.shutdownNow();  }  
}

3. 使用CompletableFuture

CompletableFuture是Java 8引入的一個類,它實現了FutureCompletionStage接口,提供了更豐富的異步編程能力。CompletableFuture可以顯式地處理異步操作的結果,并且可以鏈式調用其他異步操作。

import java.util.concurrent.CompletableFuture;  public class CompletableFutureExample {  // 模擬耗時任務的Runnable  static Runnable longRunningTask = () -> {  try {  // 模擬耗時操作  Thread.sleep(5000);  System.out.println("耗時任務完成!");  } catch (InterruptedException e) {  Thread.currentThread().interrupt();  }  };  public static void main(String[] args) {  // 使用runAsync方法提交一個異步任務,但不關心其結果  CompletableFuture.runAsync(longRunningTask);  // 如果我們想處理異步任務的結果,可以使用supplyAsync(返回結果)或thenApply等方法  // 例如:  CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {  // 模擬耗時操作并返回結果  try {  Thread.sleep(3000);  } catch (InterruptedException e) {  Thread.currentThread().interrupt();  }  return "異步任務結果";  });  // 鏈式調用處理結果  future.thenAccept(result -> System.out.println("處理結果: " + result));  // 主線程繼續執行其他任務  System.out.println("主線程正在執行其他任務...");  // 注意:main方法會立即結束,因為CompletableFuture的操作是異步的。  // 如果需要等待異步任務完成,可以調用future.join()(但注意,CompletableFuture沒有join方法,這里只是示意)  // 或者使用future.get(),但這會阻塞當前線程直到任務完成。  // 為了演示,我們可以簡單地讓主線程等待一段時間  try {  Thread.sleep(6000); // 等待足夠長的時間以確保異步任務完成  } catch (InterruptedException e) {  Thread.currentThread().interrupt();  }  }  
}  // 注意:上面的CompletableFuture示例中,我使用了Thread.sleep來模擬等待異步任務完成,  
// 這在實際應用中通常不是最佳實踐。在實際應用中,我們可能需要更復雜的邏輯來處理異步任務的結果。

請注意,CompletableFutureget()方法會阻塞當前線程直到異步任務完成,這與Future.get()的行為相同。

4. 如何在Java中實現異步運行

在Java中實現異步運行,通常指的是在不阻塞當前線程的情況下執行耗時操作或長時間運行的任務。Java提供了多種機制來實現異步編程,包括使用ExecutorServiceCompletableFutureFuture接口,以及Java 9及以后版本中引入的Flow.PublisherFlow.Subscriber(Reactive Streams API)等。以下是幾種常見的實現異步運行的方法:

4.1 使用ExecutorService

ExecutorServicejava.util.concurrent包中的一個接口,它提供了一種管理線程池的方法,允許我們提交任務給線程池中的線程執行,而不需要顯式地創建和管理線程。

import java.util.concurrent.ExecutorService; ?
import java.util.concurrent.Executors; ?public class AsyncExecutorService { ?public static void main(String[] args) { ?// 創建一個固定大小的線程池 ?ExecutorService executor = Executors.newFixedThreadPool(2); ?// 提交任務給線程池執行 ?executor.submit(() -> { ?// 耗時任務 ?System.out.println("異步任務開始執行..."); ?try { ?Thread.sleep(5000); // 模擬耗時操作 ?} catch (InterruptedException e) { ?Thread.currentThread().interrupt(); ?} ?System.out.println("異步任務執行完成!"); ?}); ?// 主線程繼續執行其他任務 ?System.out.println("主線程繼續執行..."); ?// 注意:通常應該關閉ExecutorService,但這里為了簡化示例沒有包含關閉代碼 ?// executor.shutdown(); ?} ?
}

4.2 使用CompletableFuture

CompletableFuture是Java 8引入的一個類,用于編寫異步代碼。它實現了FutureCompletionStage接口,提供了豐富的API來處理異步編程中的結果。

import java.util.concurrent.CompletableFuture;  public class AsyncCompletableFuture {  public static void main(String[] args) {  // 使用supplyAsync提交一個返回結果的異步任務  CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {  // 耗時任務  try {  Thread.sleep(5000); // 模擬耗時操作  } catch (InterruptedException e) {  Thread.currentThread().interrupt();  }  return "異步任務結果";  });  // 異步處理結果  future.thenAccept(result -> System.out.println("處理結果: " + result));  // 主線程繼續執行其他任務  System.out.println("主線程繼續執行...");  // 注意:通常不需要顯式等待CompletableFuture完成,因為它會自動在后臺執行  // 但如果我們需要等待結果,可以使用future.join()(注意:CompletableFuture沒有join方法,這里只是示意)  // 或者使用future.get(),但這會阻塞當前線程  }  
}  // 注意:CompletableFuture沒有join方法,但我們可以使用future.get()來阻塞等待結果,  
// 或者使用future.thenRun(Runnable)等方法來在任務完成后執行某些操作,而不會阻塞當前線程。

4.3 使用Future

雖然Future接口本身不提供直接創建異步任務的方法,但它通常與ExecutorService一起使用來接收異步執行的結果。

import java.util.concurrent.ExecutorService; ?
import java.util.concurrent.Executors; ?
import java.util.concurrent.Future; ?public class AsyncFuture { ?public static void main(String[] args) throws Exception { ?// 創建一個ExecutorService ?ExecutorService executor = Executors.newSingleThreadExecutor(); ?// 提交任務并獲取Future對象 ?Future<String> future = executor.submit(() -> { ?// 耗時任務 ?Thread.sleep(5000); // 模擬耗時操作 ?return "異步任務結果"; ?}); ?// 主線程繼續執行其他任務 ?System.out.println("主線程繼續執行..."); ?// 等待異步任務完成并獲取結果 ?// 注意:這會阻塞當前線程直到任務完成 ?String result = future.get(); ?System.out.println("異步任務結果: " + result); ?// 關閉ExecutorService ?executor.shutdown(); ?} ?
}

4.4 總結

以上是在Java中實現異步運行的幾種常見方法。選擇哪種方法取決于我們的具體需求,比如是否需要處理異步結果、是否需要控制線程池的大小、是否偏好使用Java 8的lambda表達式等。在實際應用中,通常建議使用ExecutorServiceCompletableFuture,因為它們提供了更靈活和強大的異步編程能力。

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

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

相關文章

【MySQL】mysql訪問

mysql訪問 1.引入MySQL 客戶端庫2.C/C 進行增刪改3.查詢的處理細節4.圖形化界面訪問數據庫4.1下載MYSQL Workbench4.2MYSQL Workbench遠程連接數據庫 點贊&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;關注&#x1f496;&#x1f496; 你的支持是對我最大的鼓勵&a…

第9章:Electron的安全性

在開發Electron應用時&#xff0c;安全性是一個非常重要的考慮因素。由于Electron應用可以訪問Node.js的全部API&#xff0c;以及使用Web技術開發界面&#xff0c;因此需要特別注意安全問題。本章將介紹如何提高Electron應用的安全性&#xff0c;包括禁用不必要的功能、設置內容…

Javascript中Object、Array、String

Object 在JavaScript中&#xff0c;Object 類型是一種復雜的數據類型&#xff0c;用于存儲鍵值對集合。它提供了多種方法來操作這些鍵值對&#xff0c;以及執行其他常見的操作。這里&#xff0c;我列出了一些 Object 類型的常見方法或特性&#xff0c;它們在日常編程中非常有用…

開思通智網-科技快報20240704:全球首個,人工智能之城,AI填報志愿

【本周新進展】 天大開發全球首個可開源片上腦機接口智能交互系統 https://tech.opensnn.com/chip/article/2826792 AI系統繪出“多彩”大腦布線圖 https://news.sciencenet.cn/htmlnews/2024/7/525678.shtm 北京亦莊將建全域人工智能之城 https://tech.opensnn.com/chip/arti…

基于深度學習的文本框檢測

基于深度學習的文本框檢測&#xff08;Text Box Detection&#xff09;是一項重要的計算機視覺任務&#xff0c;旨在從圖像中自動檢測和定位文本區域。它在光學字符識別&#xff08;OCR&#xff09;、自動文檔處理、交通標志識別等領域具有廣泛的應用。以下是關于這一領域的系統…

快遞物流運輸中的鎖控系統優缺點探討

一、物流運輸中鎖控系統的重要性 1.1 保障貨物安全 在物流運輸過程中&#xff0c;貨物安全是物流公司最為關注的問題之一。傳統機械鎖雖然在一定程度上提供了安全保障&#xff0c;但其缺點逐漸暴露&#xff0c;成為物流運輸中的一個痛點。 易被破解&#xff1a;傳統機械鎖通…

drawio打開不顯示,不在當前屏幕的解決方案

如果把drawio拖在外接顯示器&#xff0c;關機前沒有拖回主屏幕&#xff0c;那么下次打開它時如果用的不是原來那個顯示器&#xff0c;它就無法正常顯示。在任務欄上能看到有它&#xff0c;但是就是顯示不出來。 經過卸載和其他的方式沒有解決&#xff0c;就想到了&#xff0c;應…

基于MCU平臺的HMI開發的性能優化與實戰(下)

繼上篇《基于MCU平臺的HMI開發的性能優化與實戰&#xff08;上&#xff09;》深入探討了提升MCU平臺HMI開發效率和應用性能的策略后&#xff0c;本文將專注于NXP i.MX RT1170 MCU平臺的儀表盤開發實踐。我們將重點介紹Qt for MCUs的優化技巧&#xff0c;展示如何通過實際案例應…

Qt:7.QWidget屬性介紹(cursor屬性-光標形狀、font屬性-控件文本樣式、tooltip屬性-控件提示信息)

目錄 一、cursor屬性-光標形狀&#xff1a; 1.1cursor屬性介紹&#xff1a; 1.2獲取當前光標形狀——cursor()&#xff1a; 1.3 設置光標的形狀——setCursor()&#xff1a; 1.4 設置自定義圖片為光標&#xff1a; 二、font屬性-控件文本樣式&#xff1a; 2.1font屬性介紹…

antd-Table-可視化數據滾動

代碼 // 使用方式 const Index () > {useScroll();return <Table />; }import { useEffect, useRef, useState } from react;export const useScroll (() > {let timer;function start() {const [isScroll, setIsScroll] useState(true);const scrollTopRef u…

代碼隨想錄算法訓練營Day59|110.字符串接龍、105.有向圖的完全可達性、106.島嶼的周長

字符串接龍 110. 字符串接龍 (kamacoder.com) 主要參考代碼隨想錄 代碼隨想錄 (programmercarl.com) 目標&#xff1a;得到從beginStr轉變為endStr所需的最少步數 過程&#xff1a;每次變換一個字母&#xff0c;每次變換的結果要在strList中。 對于一個圖來說&#xff0c;…

excel批量修改一列單價的金額并保留1位小數

1.打開表格&#xff0c;要把單價金額變成現在的兩倍&#xff0c;數據如下&#xff1a; 2.把單價這一列粘貼到一個新的sheet頁面&#xff0c;在B2單元格輸入公式&#xff1a;A2*2 然后按enter回車鍵,這時候吧鼠標放到B2單元格右下角&#xff0c;會出現一個黑色的小加號&#xf…

重大更新來襲!!《植物大戰僵尸雜交版V2.1+修改器+融合版》

大家好&#xff01;每個軟件更新總是令人興奮不已。前段時間介紹的《植物大戰僵尸》系列以其獨特的策略玩法和豐富的植物角色&#xff0c;贏得了很多玩家的喜愛。而在今天&#xff0c;這款經典游戲全網最新版本——《植物大戰僵尸&#xff1a;雜交版V2.1》正式推出&#xff0c;…

docker 環境下failed to start lsb故障解決

背景&#xff1a;從深信服超融合遷移虛擬機到VMWARE集群后&#xff0c;遷移后的虛擬機 centos 7 運行systemctl start network ,報錯 Restarting network (via systemctl): Job for network.service failed. See systemctl status network.service and journalctl -xn for d…

Redis組建哨兵模式

主172.17.60.131 從172.17.60.130、172.17.60.129 redis部署 [rootlocalhost app]# tar xf redis-6.2.9.tar.gz [rootlocalhost app]# cd redis-6.2.9/ [rootlocalhost redis-6.2.9]# make MALLOClibc [rootlocalhost redis-6.2.9]# make install PREFIX/usr/local/redis…

Docker 中查看及修改 Redis 容器密碼的實用指南

在使用 Docker 部署 Redis 容器時&#xff0c;有時我們需要查看或修改 Redis 的密碼。本文將詳細介紹如何在 Docker 中查看和修改 Redis 容器的密碼&#xff0c;幫助你更好地管理和維護你的 Redis 實例。 一、查看 Redis 容器密碼 通常在啟動 Redis 容器時&#xff0c;我們會…

構建LangChain應用程序的示例代碼:56、如何實現一個多智能體模擬,其中沒有固定的發言順序。智能體自行決定誰來發言,通過競價機制實現

多智能體分散式發言人選擇 示例展示了如何實現一個多智能體模擬,其中沒有固定的發言順序。智能體自行決定誰來發言,通過競價機制實現。 我們將在下面的示例中展示一場虛構的總統辯論來演示這一過程。 導入LangChain相關模塊 from typing import Callable, Listimport tenac…

正向代理反向代理

nginx的正向代理和反向代理: 正向代理以及緩存配置: 代理:客戶端不再是直接訪問服務端&#xff0c;通過代理服務器訪問服務端。 正向代理&#xff1a;面向客戶端&#xff0c;通過代理服務器的ip地址訪問目標服務端 服務端只知道代理服務器的地址&#xff0c;真正的客戶端ip可以…

【MySQL系列】隱式轉換

&#x1f49d;&#x1f49d;&#x1f49d;歡迎來到我的博客&#xff0c;很高興能夠在這里和您見面&#xff01;希望您在這里可以感受到一份輕松愉快的氛圍&#xff0c;不僅可以獲得有趣的內容和知識&#xff0c;也可以暢所欲言、分享您的想法和見解。 推薦:kwan 的首頁,持續學…

ctfshow web入門 nodejs

web334 有個文件下載之后改后綴為zip加壓就可以得到兩個文件 一個文件類似于index.php 還有一個就是登錄密碼登錄成功就有flag username:ctfshow password:123456因為 return name!CTFSHOW && item.username name.toUpperCase() && item.password passwor…