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

Java實(shí)現(xiàn)中斷線程算法的代碼詳解

 更新時(shí)間:2025年08月01日 10:54:15   作者:Katie。  
在多線程編程中,線程的創(chuàng)建、運(yùn)行和終止是并發(fā)控制的核心,Java 提供了 Thread.interrupt() 與 InterruptedException 機(jī)制,允許線程之間通過中斷標(biāo)志進(jìn)行協(xié)調(diào),本項(xiàng)目將以Java 實(shí)現(xiàn)線程中斷算法為主題,深度剖析中斷機(jī)制原理,需要的朋友可以參考下

一、項(xiàng)目背景詳細(xì)介紹

在多線程編程中,線程的創(chuàng)建、運(yùn)行和終止是并發(fā)控制的核心。Java 提供了 Thread.interrupt()InterruptedException 機(jī)制,允許線程之間通過“中斷標(biāo)志”進(jìn)行協(xié)調(diào),優(yōu)雅地請(qǐng)求某個(gè)線程停止其當(dāng)前或未來的工作。但實(shí)際開發(fā)中,許多初學(xué)者對(duì)中斷機(jī)制存在誤解:

  • 誤以為調(diào)用 interrupt() 即可強(qiáng)制終止線程;
  • 忽略 InterruptedException,導(dǎo)致中斷信號(hào)被吞噬;
  • 未在業(yè)務(wù)循環(huán)或阻塞調(diào)用中及時(shí)檢查中斷狀態(tài)。

正確使用線程中斷不僅能避免強(qiáng)制停止帶來的資源不一致,還能讓線程根據(jù)業(yè)務(wù)需要決定退出時(shí)機(jī),實(shí)現(xiàn)“可控關(guān)閉”與“快速響應(yīng)”并發(fā)任務(wù)終止請(qǐng)求。本項(xiàng)目將以“Java 實(shí)現(xiàn)線程中斷算法”為主題,深度剖析中斷機(jī)制原理,構(gòu)建多種場(chǎng)景演示,幫助大家系統(tǒng)掌握如何優(yōu)雅地中斷線程及應(yīng)對(duì)常見陷阱。

二、項(xiàng)目需求詳細(xì)介紹

核心功能

演示如何在:

  • 忙循環(huán) 中檢查并響應(yīng)中斷;
  • 阻塞調(diào)用Thread.sleep、Object.wait、BlockingQueue.take 等)中捕獲并處理 InterruptedException;
  • I/O 操作InputStream.read)中響應(yīng)中斷;

提供一個(gè)通用的 InterruptibleTask 抽象類,封裝中斷檢查和資源清理框架,子類只需實(shí)現(xiàn) doWork() 方法。

實(shí)現(xiàn)一個(gè) ThreadInterrupter 工具類,用于啟動(dòng)、監(jiān)控并中斷測(cè)試線程,打印終止流程日志。

支持以下場(chǎng)景:

  • 無限循環(huán)任務(wù):立即退出;
  • 周期性任務(wù):在循環(huán)中定時(shí)調(diào)用 sleep 并響應(yīng)中斷;
  • 阻塞隊(duì)列任務(wù):從 LinkedBlockingQueue 中取數(shù)據(jù),被 interrupt() 時(shí)拋出 InterruptedException
  • I/O 讀線程:阻塞在 read(),調(diào)用 close()interrupt() 時(shí)退出。

性能需求

  • 各種場(chǎng)景中斷響應(yīng)時(shí)間在毫秒級(jí);
  • 中斷處理邏輯對(duì)業(yè)務(wù)無明顯額外開銷。

接口設(shè)計(jì)

public abstract class InterruptibleTask implements Runnable {
    protected volatile boolean stopped = false;
    protected abstract void doWork() throws Exception;
    protected void cleanup() { /* 資源清理 */ }
    @Override
    public void run() {
        try { while (!stopped) doWork(); }
        catch (InterruptedException ie) { Thread.currentThread().interrupt(); }
        catch (Exception e) { e.printStackTrace(); }
        finally { cleanup(); }
    }
    public void stop() { stopped = true; }
}

以及

public class ThreadInterrupter {
    public static void interruptAndJoin(Thread t, long timeoutMs);
}

異常處理

  • InterruptedException 必須捕獲并正確恢復(fù)中斷標(biāo)志;
  • 其他業(yè)務(wù)異常在 run 中打印或記錄,不阻塞終止流程。

測(cè)試用例

  • 啟動(dòng)多種 InterruptibleTask,延遲一定時(shí)間后調(diào)用 thread.interrupt() 和/或 task.stop(),觀察日志輸出,驗(yàn)證線程正常退出。

三、相關(guān)技術(shù)詳細(xì)介紹

中斷原理

  • Thread.interrupt():設(shè)置目標(biāo)線程的中斷標(biāo)志位;

被阻塞 的線程(在 sleep、wait、join、BlockingQueue 等)將立即拋出 InterruptedException,并清除中斷標(biāo)志;

非阻塞 的線程需自行調(diào)用 Thread.interrupted()Thread.currentThread().isInterrupted() 檢查標(biāo)志;

正確做法是在捕獲 InterruptedException 后調(diào)用 Thread.currentThread().interrupt() 恢復(fù)中斷狀態(tài),以便上層或后續(xù)業(yè)務(wù)繼續(xù)檢測(cè)。

Java 阻塞 API

  • Thread.sleep(long ms)
  • Object.wait()wait(timeout)
  • Thread.join()join(timeout)
  • BlockingQueue.puttake
  • Selector.select() 等 NIO 阻塞

I/O 中斷

  • Java NIO 通道(InterruptibleChannel)在中斷時(shí)會(huì)關(guān)閉通道并拋出 ClosedByInterruptException;
  • 老式 I/O (InputStream.read) 不響應(yīng) interrupt(),需另外調(diào)用 close();

資源清理

  • finally 塊中關(guān)閉流、釋放鎖、取消注冊(cè),避免泄漏;

四、實(shí)現(xiàn)思路詳細(xì)介紹

抽象任務(wù)框架

定義 InterruptibleTask

  • stopped 標(biāo)志配合 interrupt() 使用,可主動(dòng)通知終止;
  • doWork() 子類實(shí)現(xiàn)具體業(yè)務(wù),可拋出 InterruptedException;
  • cleanup() 提供資源釋放鉤子。

工具類

ThreadInterrupter.interruptAndJoin(Thread, timeout)

  • 調(diào)用 t.interrupt()
  • t.join(timeout);
  • 如果仍存活,可打印警告或調(diào)用 stop()。

示例場(chǎng)景

  • BusyLoopTask:在循環(huán)中定期調(diào)用 Thread.sleep(100) 以模擬工作,可迅速響應(yīng)中斷;
  • BlockingQueueTask:在 take() 上阻塞,interrupt()thread.interrupt() 將使其拋出 InterruptedException
  • IOReadTask:使用 PipedInputStreamPipedOutputStream 演示傳統(tǒng) I/O,在中斷時(shí)調(diào)用 close()

監(jiān)控與日志

  • 每個(gè)任務(wù)在 run 開始和結(jié)束時(shí)打印日志;
  • 工具類在中斷和 join 后打印狀態(tài);

五、完整實(shí)現(xiàn)代碼

// 文件:InterruptibleTask.java
package com.example.threadinterrupt;
 
public abstract class InterruptibleTask implements Runnable {
    // 可選的主動(dòng)停止標(biāo)志
    protected volatile boolean stopped = false;
 
    /** 子類實(shí)現(xiàn)具體工作邏輯,支持拋出 InterruptedException */
    protected abstract void doWork() throws Exception;
 
    /** 資源清理(流/鎖/注冊(cè)等),可由子類覆蓋 */
    protected void cleanup() { }
 
    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        System.out.printf("[%s] 開始執(zhí)行%n", name);
        try {
            while (!stopped && !Thread.currentThread().isInterrupted()) {
                doWork();
            }
        } catch (InterruptedException ie) {
            // 恢復(fù)中斷狀態(tài),允許外層檢測(cè)
            Thread.currentThread().interrupt();
            System.out.printf("[%s] 捕獲 InterruptedException,準(zhǔn)備退出%n", name);
        } catch (Exception e) {
            System.err.printf("[%s] 出現(xiàn)異常: %s%n", name, e);
            e.printStackTrace();
        } finally {
            cleanup();
            System.out.printf("[%s] 已退出%n", name);
        }
    }
 
    /** 主動(dòng)請(qǐng)求停止(可選) */
    public void stop() {
        stopped = true;
    }
}
 
// ----------------------------------------------------------------
// 文件:ThreadInterrupter.java
package com.example.threadinterrupt;
 
public class ThreadInterrupter {
    /**
     * 中斷線程并等待退出
     * @param t         目標(biāo)線程
     * @param timeoutMs 等待退出超時(shí)時(shí)間(毫秒)
     */
    public static void interruptAndJoin(Thread t, long timeoutMs) {
        System.out.printf("[Interrupter] 中斷線程 %s%n", t.getName());
        t.interrupt();
        try {
            t.join(timeoutMs);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        if (t.isAlive()) {
            System.err.printf("[Interrupter] 線程 %s 未能在 %d ms 內(nèi)退出%n",
                    t.getName(), timeoutMs);
        } else {
            System.out.printf("[Interrupter] 線程 %s 已退出%n", t.getName());
        }
    }
}
 
// ----------------------------------------------------------------
// 文件:BusyLoopTask.java
package com.example.threadinterrupt;
 
public class BusyLoopTask extends InterruptibleTask {
    private int counter = 0;
    @Override
    protected void doWork() throws InterruptedException {
        // 模擬業(yè)務(wù):每100ms自增一次
        Thread.sleep(100);
        System.out.printf("[BusyLoop] %s:計(jì)數(shù) %d%n",
                Thread.currentThread().getName(), ++counter);
    }
}
 
// ----------------------------------------------------------------
// 文件:BlockingQueueTask.java
package com.example.threadinterrupt;
 
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
 
public class BlockingQueueTask extends InterruptibleTask {
    private final BlockingQueue<String> queue = new LinkedBlockingQueue<>();
 
    public BlockingQueueTask() {
        // 先放一個(gè)元素供 take
        queue.offer("初始數(shù)據(jù)");
    }
 
    @Override
    protected void doWork() throws InterruptedException {
        String data = queue.take();  // 阻塞等待
        System.out.printf("[BlockingQueue] %s:取到數(shù)據(jù) %s%n",
                Thread.currentThread().getName(), data);
    }
}
 
// ----------------------------------------------------------------
// 文件:IOReadTask.java
package com.example.threadinterrupt;
 
import java.io.*;
 
public class IOReadTask extends InterruptibleTask {
    private PipedInputStream in;
    private PipedOutputStream out;
 
    public IOReadTask() throws IOException {
        in = new PipedInputStream();
        out = new PipedOutputStream(in);
        // 啟動(dòng)寫線程,模擬持續(xù)寫入
        new Thread(() -> {
            try {
                int i = 0;
                while (true) {
                    out.write(("msg" + i++ + "\n").getBytes());
                    Thread.sleep(200);
                }
            } catch (Exception ignored) { }
        }, "Writer").start();
    }
 
    @Override
    protected void doWork() throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        String line = reader.readLine(); // 阻塞在 readLine
        System.out.printf("[IORead] %s:讀到 %s%n",
                Thread.currentThread().getName(), line);
    }
 
    @Override
    protected void cleanup() {
        try { in.close(); out.close(); } catch (IOException ignored) { }
        System.out.printf("[IORead] %s:已關(guān)閉流%n", Thread.currentThread().getName());
    }
}
 
// ----------------------------------------------------------------
// 文件:Main.java
package com.example.threadinterrupt;
 
public class Main {
    public static void main(String[] args) throws Exception {
        // 創(chuàng)建并啟動(dòng)任務(wù)
        BusyLoopTask busy = new BusyLoopTask();
        Thread t1 = new Thread(busy, "BusyLoop-Thread");
        t1.start();
 
        BlockingQueueTask bq = new BlockingQueueTask();
        Thread t2 = new Thread(bq, "BlockingQueue-Thread");
        t2.start();
 
        IOReadTask io = new IOReadTask();
        Thread t3 = new Thread(io, "IORead-Thread");
        t3.start();
 
        // 運(yùn)行 2 秒后中斷
        Thread.sleep(2000);
        ThreadInterrupter.interruptAndJoin(t1, 500);
        ThreadInterrupter.interruptAndJoin(t2, 500);
        ThreadInterrupter.interruptAndJoin(t3, 500);
    }
}

六、代碼詳細(xì)解讀

InterruptibleTask

統(tǒng)一在 run() 中檢查 stoppedisInterrupted();

catch (InterruptedException) 中調(diào)用 Thread.currentThread().interrupt() 恢復(fù)中斷標(biāo)志;

finally 中調(diào)用 cleanup(),保證資源釋放。

ThreadInterrupter.interruptAndJoin

  • 調(diào)用 thread.interrupt() 發(fā)送中斷請(qǐng)求;
  • join(timeout) 等待指定時(shí)間;
  • 根據(jù) isAlive() 判斷線程是否已退出并打印日志。

BusyLoopTask

  • 每 100ms sleep 后打印計(jì)數(shù),sleep 拋中斷時(shí)捕獲并退出循環(huán)。

BlockingQueueTask

  • queue.take() 上阻塞,收到中斷時(shí) take()InterruptedException,退出循環(huán)。

IOReadTask

  • 使用 PipedInputStream/PipedOutputStream 模擬阻塞 I/O;
  • readLine() 上阻塞,收到中斷后通過 in.close() 觸發(fā) IOException 或 NIO 異常,退出。
  • cleanup() 中關(guān)閉流,避免資源泄漏。

Main

  • 啟動(dòng)三種任務(wù),運(yùn)行 2 秒后統(tǒng)一中斷并等待退出,觀察日志驗(yàn)證各自的中斷響應(yīng)時(shí)機(jī)與清理邏輯。

七、項(xiàng)目詳細(xì)總結(jié)

通過本項(xiàng)目的示例,我們對(duì) Java 線程中斷機(jī)制有了更系統(tǒng)的理解:

  • interrupt() 只發(fā)出中斷請(qǐng)求,不強(qiáng)制殺死線程;
  • 阻塞非阻塞 場(chǎng)景的中斷響應(yīng)方式不同,必須根據(jù) API 特性在代碼中主動(dòng)檢查或捕獲 InterruptedException
  • 正確的中斷處理需在 catch 中恢復(fù)中斷標(biāo)志,并在 finally 中釋放資源;
  • 構(gòu)建通用的 InterruptibleTask 抽象框架,可以極大簡(jiǎn)化業(yè)務(wù)開發(fā),實(shí)現(xiàn)高復(fù)用。

八、項(xiàng)目常見問題及解答

Q:interrupt()stop() 的區(qū)別?
Astop() 已廢棄,會(huì)強(qiáng)制釋放鎖,可能導(dǎo)致數(shù)據(jù)不一致;interrupt() 是協(xié)作式,不破壞資源一致性。

Q:為什么要在 catch 中調(diào)用 Thread.currentThread().interrupt()?
AInterruptedException 拋出后中斷標(biāo)志被清除,需恢復(fù)以便后續(xù)或上層代碼繼續(xù)檢測(cè)。

Q:傳統(tǒng) I/O(InputStream.read)會(huì)響應(yīng)中斷嗎?
A:不會(huì)。需要在另一個(gè)線程調(diào)用 close() 來使其拋出異常,或使用 NIO 通道。

Q:如何優(yōu)雅停止長(zhǎng)期阻塞的 NIO Selector.select()?
A:可調(diào)用 selector.wakeup() 或關(guān)閉 Selector,而非 interrupt()。

Q:中斷后任務(wù)如何保證冪等?
A:在 cleanup() 中需考慮業(yè)務(wù)重入與狀態(tài)回滾,避免部分操作執(zhí)行兩次。

九、擴(kuò)展方向與性能優(yōu)化

  • 更多阻塞 API:演示 ReentrantLock.lockInterruptibly()CountDownLatch.await()、Semaphore.acquire() 等場(chǎng)景下中斷響應(yīng);
  • 線程池中斷:結(jié)合 ThreadPoolExecutor.shutdownNow()Future.cancel(true) 進(jìn)行批量中斷;
  • 自定義中斷策略:支持“優(yōu)雅關(guān)閉”與“強(qiáng)制關(guān)閉”兩種模式,讓調(diào)用者按需選擇;
  • 監(jiān)控集成:將中斷日志與 JMX 或 Prometheus 指標(biāo)結(jié)合,實(shí)時(shí)觀察線程退出率與健康狀態(tài);
  • 中斷回調(diào):為任務(wù)提供回調(diào)接口,在線程被中斷時(shí)自動(dòng)執(zhí)行特定邏輯(如狀態(tài)上報(bào)、補(bǔ)償操作);
  • 庫(kù)化發(fā)布:將上述框架封裝為 Maven 坐標(biāo),可在多個(gè)項(xiàng)目中復(fù)用,減少重復(fù)工作。

以上就是Java實(shí)現(xiàn)中斷線程算法的代碼詳解的詳細(xì)內(nèi)容,更多關(guān)于Java中斷線程算法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Spring中異步注解@Async的使用、原理及使用時(shí)可能導(dǎo)致的問題及解決方法

    Spring中異步注解@Async的使用、原理及使用時(shí)可能導(dǎo)致的問題及解決方法

    這篇文章主要介紹了Spring中異步注解@Async的使用、原理及使用時(shí)可能導(dǎo)致的問題及解決方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-07-07
  • Java中equals方法使用及重寫練習(xí)

    Java中equals方法使用及重寫練習(xí)

    equals是在object類中的方法,在object中equals是用來看看兩個(gè)參數(shù)是否引用的是同一個(gè)對(duì)象,下面這篇文章主要給大家介紹了關(guān)于Java中equals方法使用及重寫練習(xí)的相關(guān)資料,需要的朋友可以參考下
    2023-05-05
  • Java?SWT中常見彈出框?qū)嵗偨Y(jié)

    Java?SWT中常見彈出框?qū)嵗偨Y(jié)

    剛開始寫Java工具的小伙伴可能不知道怎么寫消息對(duì)話框,在這里總結(jié)一些常用的幾種消息彈出框,下面這篇文章主要給大家介紹了關(guān)于Java?SWT中常見彈出框的相關(guān)資料,需要的朋友可以參考下
    2023-01-01
  • java 枚舉類中的valueOf用法說明

    java 枚舉類中的valueOf用法說明

    這篇文章主要介紹了java 枚舉類中的valueOf用法說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java 二分查找算法的實(shí)現(xiàn)

    Java 二分查找算法的實(shí)現(xiàn)

    這篇文章主要介紹了Java 如何實(shí)現(xiàn)二分查找算法,幫助大家更好的理解和學(xué)習(xí)Java 算法,感興趣的朋友可以了解下
    2020-09-09
  • ?Spring?中?Bean?的生命周期詳解

    ?Spring?中?Bean?的生命周期詳解

    這篇文章主要介紹了Spring中Bean的生命周期詳解,Java中的公共類稱之為Bean或Java?Bean,而Spring中的Bean指的是將對(duì)象的生命周期
    2022-09-09
  • java?Spring的啟動(dòng)原理詳解

    java?Spring的啟動(dòng)原理詳解

    大家好,本篇文章主要講的是java?Spring的啟動(dòng)原理詳解,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下
    2022-01-01
  • maven 指定version不生效的問題

    maven 指定version不生效的問題

    這篇文章主要介紹了maven 指定version不生效的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • Java多線程案例實(shí)戰(zhàn)之定時(shí)器的實(shí)現(xiàn)

    Java多線程案例實(shí)戰(zhàn)之定時(shí)器的實(shí)現(xiàn)

    在Java中可以使用多線程和定時(shí)器來實(shí)現(xiàn)定時(shí)任務(wù),下面這篇文章主要給大家介紹了關(guān)于Java多線程案例之定時(shí)器實(shí)現(xiàn)的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-01-01
  • Java數(shù)據(jù)結(jié)構(gòu)之棧的詳解

    Java數(shù)據(jù)結(jié)構(gòu)之棧的詳解

    這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)之棧簡(jiǎn)單操作的相關(guān)資料,需要的朋友可以參考下,希望能夠給你帶來幫助
    2021-09-09

最新評(píng)論