欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文詳解如何在Java中啟動(dòng)線程

 更新時(shí)間:2024年07月10日 08:58:47   作者:老譚說架構(gòu)  
今天要跟大家聊一聊Java多線程的原理和使用方式,Java多線程是提高程序性能的重要機(jī)制,了解線程生命周期、同步機(jī)制、線程池和線程間通信等概念,可以幫助我們編寫出高效、可靠的多線程程序,需要的朋友可以參考下

1. 簡介

今天要跟大家聊一聊Java多線程的原理和使用方式,Java多線程是提高程序性能的重要機(jī)制。了解線程生命周期、同步機(jī)制、線程池和線程間通信等概念,可以幫助我們編寫出高效、可靠的多線程程序。

Java 線程的生命周期可以分為以下幾個(gè)狀態(tài):

1. 新建 (New):  當(dāng)使用 new Thread() 創(chuàng)建線程對(duì)象時(shí),線程處于新建狀態(tài)。此時(shí)線程尚未啟動(dòng),還沒有分配系統(tǒng)資源。

2. 就緒 (Runnable):  當(dāng)調(diào)用線程對(duì)象的 start() 方法時(shí),線程進(jìn)入就緒狀態(tài)。此時(shí)線程已準(zhǔn)備好運(yùn)行,但尚未獲得 CPU 時(shí)間片,需要等待操作系統(tǒng)分配。

3. 運(yùn)行 (Running):  線程獲得 CPU 時(shí)間片,開始執(zhí)行線程體代碼,進(jìn)入運(yùn)行狀態(tài)。

4. 阻塞 (Blocked):  當(dāng)線程遇到以下情況時(shí),會(huì)進(jìn)入阻塞狀態(tài):

  • 等待 (Waiting):  線程調(diào)用 Object.wait() 方法等待某個(gè)特定事件發(fā)生。
  • 睡眠 (Sleeping):  線程調(diào)用 Thread.sleep() 方法進(jìn)入睡眠狀態(tài),等待一段時(shí)間后自動(dòng)恢復(fù)運(yùn)行。
  • I/O 阻塞:  線程等待 I/O 操作完成,例如讀取文件或網(wǎng)絡(luò)數(shù)據(jù)。
  • 鎖阻塞:  線程試圖獲取某個(gè)鎖,但鎖被其他線程占用,導(dǎo)致阻塞。

5. 終止 (Terminated):  線程執(zhí)行完 run() 方法中的代碼,或者遇到異常而退出,進(jìn)入終止?fàn)顟B(tài)。

線程狀態(tài)轉(zhuǎn)換:

  • 新建 -> 就緒: 調(diào)用 start() 方法。
  • 就緒 -> 運(yùn)行: 操作系統(tǒng)分配 CPU 時(shí)間片。
  • 運(yùn)行 -> 阻塞: 線程遇到等待、睡眠、I/O 阻塞、鎖阻塞等情況。
  • 阻塞 -> 就緒: 等待的事件發(fā)生、睡眠時(shí)間結(jié)束、I/O 操作完成、獲得鎖。
  • 運(yùn)行 -> 終止: run() 方法執(zhí)行完畢、遇到異常。

其他重要概念:

  • 守護(hù)線程 (Daemon Thread):  守護(hù)線程是為其他線程服務(wù)的線程,例如垃圾回收線程。當(dāng)所有非守護(hù)線程都終止后,守護(hù)線程也會(huì)自動(dòng)終止。
  • 線程優(yōu)先級(jí) (Thread Priority):  線程可以設(shè)置優(yōu)先級(jí),優(yōu)先級(jí)高的線程更容易獲得 CPU 時(shí)間片。

2. 運(yùn)行線程的基礎(chǔ)知識(shí)

我們可以利用Thread框架輕松的編寫一些在并行線程中運(yùn)行的邏輯。

讓我們嘗試一個(gè)基本的例子,通過擴(kuò)展Thread類:

public class NewThread extends Thread {
    public void run() {
        long startTime = System.currentTimeMillis();
        int i = 0;
        while (true) {
            System.out.println(this.getName() + ": New Thread is running..." + i++);
            try {
                //Wait for one sec so it doesn't print too fast
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ...
        }
    }
}

現(xiàn)在我們編寫第二個(gè)類來初始化并啟動(dòng)我們的線程:

public class SingleThreadExample {
    public static void main(String[] args) {
        NewThread t = new NewThread();
        t.start();
    }
}

我們應(yīng)該 對(duì)處于NEW狀態(tài)(相當(dāng)于未啟動(dòng))的線程 調(diào)用start()方法。否則,Java 將拋出IllegalThreadStateException異常的實(shí)例。

現(xiàn)在假設(shè)我們需要啟動(dòng)多個(gè)線程:

public class MultipleThreadsExample {
    public static void main(String[] args) {
        NewThread t1 = new NewThread();
        t1.setName("MyThread-1");
        NewThread t2 = new NewThread();
        t2.setName("MyThread-2");
        t1.start();
        t2.start();
    }
}

我們的代碼看起來仍然非常簡單并且與我們?cè)诰W(wǎng)上找到的示例非常相似。

當(dāng)然,這與可用于生產(chǎn)的代碼還相去甚遠(yuǎn),以正確的方式管理資源至關(guān)重要,以避免過多的上下文切換或過多的內(nèi)存使用。

因此,為了做好生產(chǎn)準(zhǔn)備,我們現(xiàn)在需要編寫額外的樣板來處理:

  • 持續(xù)創(chuàng)建新線程
  • 并發(fā)活動(dòng)線程數(shù)
  • 線程釋放:對(duì)于守護(hù)線程來說非常重要,可以避免泄漏

如果我們?cè)敢?,我們可以為所有這些情況甚至更多情況編寫自己的代碼,但我們?yōu)槭裁匆匦掳l(fā)明輪子呢?

3. ExecutorService框架

ExecutorService實(shí)現(xiàn)了線程池設(shè)計(jì)模式(也稱為復(fù)制工作器或工作組模型),并負(fù)責(zé)我們上面提到的線程管理,此外它還添加了一些非常有用的功能,如線程可重用性和任務(wù)隊(duì)列 。

線程可重用性尤其重要:在大型應(yīng)用程序中,分配和釋放許多線程對(duì)象會(huì)產(chǎn)生大量內(nèi)存管理開銷。

利用工作線程,我們可以最大限度地減少線程創(chuàng)建造成的開銷。 為了簡化池配置,ExecutorService帶有一個(gè)簡單的構(gòu)造函數(shù)和一些自定義選項(xiàng),例如隊(duì)列的類型、最小和最大線程數(shù)及其命名約定。

4. 使用執(zhí)行器啟動(dòng)任務(wù)

有了這個(gè)強(qiáng)大的框架,我們可以把思維從啟動(dòng)線程轉(zhuǎn)變?yōu)樘峤蝗蝿?wù)。

讓我們看看如何向執(zhí)行器提交異步任務(wù):

ExecutorService executor = Executors.newFixedThreadPool(10);
...
executor.submit(() -> {
    new Task();
});

我們可以使用兩種方法:execute(不返回任何內(nèi)容)和submit(返回封裝了計(jì)算結(jié)果的Future )。

5. 使用CompletableFutures啟動(dòng)任務(wù)

要從Future對(duì)象中檢索最終結(jié)果,我們可以使用 該對(duì)象中可用的get 方法,但這會(huì)阻塞父線程,直到計(jì)算結(jié)束。

或者,我們可以通過在任務(wù)中添加更多邏輯來避免阻塞,但我們必須增加代碼的復(fù)雜性。 Java 1.8 在Future構(gòu)造之上引入了一個(gè)新框架,以便更好地處理計(jì)算結(jié)果:CompletableFuture。

CompletableFuture 實(shí)現(xiàn)了CompletableStage,它增加了大量方法來附加回調(diào)并避免了在結(jié)果準(zhǔn)備好后運(yùn)行操作所需的所有管道。

提交任務(wù)的實(shí)現(xiàn)就簡單多了:

CompletableFuture.supplyAsync(() -> "Hello");

supplyAsync接受一個(gè)Supplier,其中包含我們想要異步執(zhí)行的代碼——在我們的例子中是 lambda 參數(shù)。

該任務(wù)現(xiàn)在隱式提交給 ForkJoinPool.commonPool() ,或者我們可以指定我們喜歡的Executor作為第二個(gè)參數(shù)。

6. 運(yùn)行延遲或周期性任務(wù)

在處理復(fù)雜的 Web 應(yīng)用程序時(shí),我們可能需要在特定時(shí)間(或許是定期)運(yùn)行任務(wù)。

Java 有一些工具可以幫助我們運(yùn)行延遲或重復(fù)的操作:

  • 定時(shí)器
  • java.util.concurrent.ScheduledThreadPoolExecutor

6.1. 計(jì)時(shí)器

計(jì)時(shí)器是一種用于安排任務(wù)在后臺(tái)線程中將來執(zhí)行的工具。

任務(wù)可以被安排一次性執(zhí)行,或者定期重復(fù)執(zhí)行。

如果我們想在延遲一秒鐘后運(yùn)行任務(wù),讓我們看看代碼是什么樣的:

TimerTask task = new TimerTask() {
    public void run() {
        System.out.println("Task performed on: " + new Date() + "n" 
          + "Thread's name: " + Thread.currentThread().getName());
    }
};
Timer timer = new Timer("Timer");
long delay = 1000L;
timer.schedule(task, delay);復(fù)制

現(xiàn)在讓我們添加一個(gè)重復(fù)的計(jì)劃:

timer.scheduleAtFixedRate(repeatedTask, delay, period);復(fù)制

這一次,任務(wù)將在指定的延遲后運(yùn)行,并且在經(jīng)過一段時(shí)間后重復(fù)運(yùn)行。

6.2. ScheduledThreadPoolExecutor

ScheduledThreadPoolExecutor具有與 Timer類 類似的方法:

ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);
ScheduledFuture<Object> resultFuture
  = executorService.schedule(callableTask, 1, TimeUnit.SECONDS);

為了結(jié)束我們的示例,我們使用 scheduleAtFixedRate() 來執(zhí)行重復(fù)任務(wù):

ScheduledFuture<Object> resultFuture
 = executorService.scheduleAtFixedRate(runnableTask, 100, 450, TimeUnit.MILLISECONDS);

上述代碼將在初始延遲 100 毫秒后執(zhí)行一項(xiàng)任務(wù),之后每 450 毫秒執(zhí)行一次相同的任務(wù)。

如果處理器不能在下一次發(fā)生之前及時(shí)完成處理任務(wù),則 ScheduledExecutorService 將等到當(dāng)前任務(wù)完成后再開始下一個(gè)任務(wù)。

為了避免這段等待時(shí)間,我們可以使用 scheduleWithFixedDelay() ,正如其名稱所述,它可以保證任務(wù)迭代之間的固定長度延遲。

6.3. 哪個(gè)工具更好?

如果我們運(yùn)行上述例子,計(jì)算的結(jié)果看起來是一樣的。

那么, 我們?nèi)绾芜x擇正確的工具?

當(dāng)一個(gè)框架提供多種選擇時(shí),了解底層技術(shù)以做出明智的決定非常重要。

讓我們嘗試更深入地探究一下。

計(jì)時(shí)器:

  • 不提供實(shí)時(shí)保證:它使用 Object.wait  (long) 方法來安排任務(wù)
  • 只有一個(gè)后臺(tái)線程,因此任務(wù)按順序運(yùn)行,長時(shí)間運(yùn)行的任務(wù)可能會(huì)延遲其他任務(wù)
  • TimerTask中拋出的運(yùn)行時(shí)異常會(huì)殺死唯一可用的線程,從而殺死Timer

ScheduledThreadPoolExecutor:

  • 可以配置任意數(shù)量的線程
  • 可以利用所有可用的 CPU 核心
  • 捕獲運(yùn)行時(shí)異常并讓我們根據(jù)需要處理它們(通過重寫ThreadPoolExecutor的 afterExecute方法)**
  • 取消引發(fā)異常的任務(wù),同時(shí)讓其他任務(wù)繼續(xù)運(yùn)行
  • 依靠操作系統(tǒng)調(diào)度系統(tǒng)來跟蹤時(shí)區(qū)、延遲、太陽時(shí)等。
  • 如果我們需要多個(gè)任務(wù)之間的協(xié)調(diào),則提供協(xié)作 API,例如等待所有提交的任務(wù)完成
  • 提供更好的 API 來管理線程生命周期

7. Future和ScheduledFuture之間的區(qū)別

在我們的代碼示例中,我們可以觀察到ScheduledThreadPoolExecutor 返回特定類型的Future:ScheduledFuture。

ScheduledFuture 擴(kuò)展了Future和Delayed接口,因此繼承了額外的方法getDelay  ,該方法返回與當(dāng)前任務(wù)相關(guān)的剩余延遲。它由RunnableScheduledFuture擴(kuò)展,并添加了一個(gè)方法來檢查任務(wù)是否是周期性的。

ScheduledThreadPoolExecutor 通過內(nèi)部類ScheduledFutureTask實(shí)現(xiàn)所有這些構(gòu)造,并使用它們來控制任務(wù)生命周期。

8. 結(jié)論

Java 多線程在各種應(yīng)用場(chǎng)景中都發(fā)揮著重要作用,可以顯著提高程序效率和響應(yīng)速度。以下列舉一些常見的 Java 多線程使用場(chǎng)景:

1. 并發(fā)處理:

  • 網(wǎng)絡(luò)應(yīng)用程序:  多個(gè)線程可以同時(shí)處理來自多個(gè)客戶端的請(qǐng)求,提高服務(wù)器的吞吐量和響應(yīng)速度。
  • 文件處理:  多個(gè)線程可以同時(shí)讀取、寫入或處理多個(gè)文件,加速文件操作。
  • 數(shù)據(jù)庫操作:  多個(gè)線程可以同時(shí)執(zhí)行數(shù)據(jù)庫查詢或更新操作,提高數(shù)據(jù)庫的并發(fā)性能。

2. 用戶界面響應(yīng):

  • 圖形界面應(yīng)用程序:  多個(gè)線程可以將耗時(shí)的操作(如圖片加載、數(shù)據(jù)處理)放到后臺(tái)執(zhí)行,避免阻塞主線程,保持用戶界面的流暢響應(yīng)。
  • 游戲開發(fā):  多個(gè)線程可以同時(shí)處理游戲邏輯、渲染圖形、播放聲音等任務(wù),提高游戲流暢度和響應(yīng)速度。

3. 并行計(jì)算:

  • 科學(xué)計(jì)算:  多個(gè)線程可以同時(shí)執(zhí)行復(fù)雜的數(shù)學(xué)計(jì)算,加速計(jì)算過程。
  • 數(shù)據(jù)分析:  多個(gè)線程可以同時(shí)處理大量數(shù)據(jù),加快數(shù)據(jù)分析速度。
  • 機(jī)器學(xué)習(xí):  多個(gè)線程可以同時(shí)訓(xùn)練模型,提高模型訓(xùn)練效率。

4. 任務(wù)調(diào)度:

  • 任務(wù)管理系統(tǒng):  多個(gè)線程可以同時(shí)執(zhí)行不同的任務(wù),提高任務(wù)處理效率。
  • 定時(shí)任務(wù):  多個(gè)線程可以按照指定的時(shí)間間隔或時(shí)間點(diǎn)執(zhí)行任務(wù)。

5. 異步操作:

  • 網(wǎng)絡(luò)通信:  使用多線程可以異步發(fā)送和接收網(wǎng)絡(luò)數(shù)據(jù),提高網(wǎng)絡(luò)通信效率。
  • 文件上傳/下載:  多線程可以異步執(zhí)行文件上傳/下載操作,避免阻塞主線程。

6. 其他應(yīng)用場(chǎng)景:

  • 多線程測(cè)試:  可以使用多線程模擬多個(gè)用戶同時(shí)訪問系統(tǒng),進(jìn)行壓力測(cè)試。
  • 并發(fā)編程框架:  許多并發(fā)編程框架(如 Akka、RxJava)都是基于多線程實(shí)現(xiàn)的。

以上就是一文詳解如何在Java中啟動(dòng)線程的詳細(xì)內(nèi)容,更多關(guān)于Java啟動(dòng)線程的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java多線程并發(fā)executorservice(任務(wù)調(diào)度)類

    java多線程并發(fā)executorservice(任務(wù)調(diào)度)類

    這篇文章主要介紹了線程并發(fā)ScheduledExecutorService類,設(shè)置 ScheduledExecutorService ,2秒后,在 1 分鐘內(nèi)每 10 秒鐘蜂鳴一次
    2014-01-01
  • 淺析Android系統(tǒng)中HTTPS通信的實(shí)現(xiàn)

    淺析Android系統(tǒng)中HTTPS通信的實(shí)現(xiàn)

    這篇文章主要介紹了淺析Android系統(tǒng)中HTTPS通信的實(shí)現(xiàn),實(shí)現(xiàn)握手的源碼為Java語言編寫,需要的朋友可以參考下
    2015-07-07
  • Java8如何通過Lambda處理List集合

    Java8如何通過Lambda處理List集合

    這篇文章主要介紹了java8如何通過Lambda處理List集合,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01
  • Java中String字符串轉(zhuǎn)具體對(duì)象的幾種常用方式

    Java中String字符串轉(zhuǎn)具體對(duì)象的幾種常用方式

    String對(duì)象可以用來存儲(chǔ)任何字符串類型的數(shù)據(jù),包括HTML、XML等格式的字符串,下面這篇文章主要給大家介紹了關(guān)于JavaString字符串轉(zhuǎn)具體對(duì)象的幾種常用方式,需要的朋友可以參考下
    2024-03-03
  • SpringBoot通過計(jì)劃任務(wù)發(fā)送郵件提醒的代碼詳解

    SpringBoot通過計(jì)劃任務(wù)發(fā)送郵件提醒的代碼詳解

    在實(shí)際線上項(xiàng)目中,有不斷接受到推送方發(fā)來的數(shù)據(jù)場(chǎng)景,而且是不間斷的發(fā)送,如果忽然間斷了,應(yīng)該是出問題了,需要及時(shí)檢查原因,這種情況比較適合用計(jì)劃任務(wù)做檢查判斷,出問題發(fā)郵件提醒,本文給大家介紹了SpringBoot通過計(jì)劃任務(wù)發(fā)送郵件提醒,需要的朋友可以參考下
    2024-11-11
  • SpringBoot使用注解集成Redis緩存的示例代碼

    SpringBoot使用注解集成Redis緩存的示例代碼

    這篇文章主要介紹了在?Spring?Boot?中使用注解集成?Redis?緩存的步驟,包括添加依賴、創(chuàng)建相關(guān)配置類、需要緩存數(shù)據(jù)的類(TestService)以及測(cè)試方法(如在?Controller?中的?redisTest?和?redisCache?方法),還對(duì)一些關(guān)鍵代碼和配置進(jìn)行了詳細(xì)說明
    2025-01-01
  • SSM項(xiàng)目中配置LOG4J日志的方法

    SSM項(xiàng)目中配置LOG4J日志的方法

    本篇文章主要介紹了SSM項(xiàng)目中配置LOG4J日志的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-09-09
  • 如何定位java程序中占用cpu最高的線程堆棧信息

    如何定位java程序中占用cpu最高的線程堆棧信息

    這篇文章主要介紹了如何定位java程序中占用cpu最高的線程堆棧信息方法的相關(guān)資料,需要的朋友可以參考下
    2022-11-11
  • Nacos與SpringBoot實(shí)現(xiàn)配置管理的開發(fā)實(shí)踐

    Nacos與SpringBoot實(shí)現(xiàn)配置管理的開發(fā)實(shí)踐

    在微服務(wù)架構(gòu)中,配置管理是一個(gè)核心組件,而Nacos為此提供了一個(gè)強(qiáng)大的解決方案,本文主要介紹了Nacos與SpringBoot實(shí)現(xiàn)配置管理的開發(fā)實(shí)踐,具有一定的參考價(jià)值
    2023-08-08
  • java正則表達(dá)式判斷 ip 地址是否正確解析

    java正則表達(dá)式判斷 ip 地址是否正確解析

    這篇文章主要介紹了java正則表達(dá)式判斷 ip 地址是否正確解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-08-08

最新評(píng)論