最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中線程執(zhí)行狀態(tài)檢測(cè)的四種可靠方法

 更新時(shí)間:2025年05月06日 08:35:09   作者:異常君  
在多線程開發(fā)中,開發(fā)者常需監(jiān)控子線程狀態(tài),這個(gè)問(wèn)題關(guān)系到系統(tǒng)的可靠性和錯(cuò)誤處理能力,需要一套完善的方案來(lái)解決,下面我們來(lái)看看四種從基礎(chǔ)到高級(jí)的解決方案吧

在多線程開發(fā)中,開發(fā)者常需監(jiān)控子線程狀態(tài)。當(dāng)主線程創(chuàng)建并啟動(dòng)多個(gè)工作線程后,如何判斷這些任務(wù)是否成功完成?工作線程因未處理異常終止時(shí),主線程往往無(wú)法直接感知。這個(gè)問(wèn)題關(guān)系到系統(tǒng)的可靠性和錯(cuò)誤處理能力,需要一套完善的方案來(lái)解決。

線程執(zhí)行狀態(tài)檢測(cè)的挑戰(zhàn)

在 Java 多線程編程中,主線程啟動(dòng)工作線程后,默認(rèn)情況下無(wú)法直接獲知工作線程的執(zhí)行結(jié)果。這是由于線程的獨(dú)立性特征決定的:

那么,如何讓主線程知道工作線程是否執(zhí)行成功呢?下面介紹四種從基礎(chǔ)到高級(jí)的解決方案。

方法一:使用 Thread.join()等待線程完成

最基礎(chǔ)的方法是調(diào)用線程的 join()方法,使主線程等待工作線程執(zhí)行完畢。

public class JoinExample {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            try {
                System.out.println("工作線程開始執(zhí)行");
                // 模擬任務(wù)執(zhí)行
                Thread.sleep(2000);
                System.out.println("工作線程執(zhí)行完成");
            } catch (InterruptedException e) {
                System.err.println("工作線程被中斷:" + e.getMessage());
                Thread.currentThread().interrupt();
            } catch (Exception e) {
                System.err.println("工作線程執(zhí)行異常:" + e.getMessage());
            }
        });

        try {
            thread.start();
            // 主線程等待工作線程執(zhí)行完成,支持設(shè)置超時(shí)
            // thread.join(3000); // 等待最多3秒
            thread.join();

            // 檢查線程狀態(tài)
            if (!thread.isAlive()) {
                System.out.println("工作線程已結(jié)束執(zhí)行");
                // 但仍無(wú)法知道是成功還是失敗
            }
        } catch (InterruptedException e) {
            System.err.println("主線程等待過(guò)程中被中斷");
            Thread.currentThread().interrupt();
        }
    }
}

局限性

  • 只能知道線程是否執(zhí)行完畢,無(wú)法獲取執(zhí)行結(jié)果或異常信息
  • 支持基礎(chǔ)的超時(shí)設(shè)置(通過(guò)join(long)),但功能有限(如超時(shí)后需手動(dòng)檢查線程狀態(tài),無(wú)法中途取消)
  • 對(duì)于多個(gè)線程,需要逐個(gè) join,代碼繁瑣

方法二:通過(guò)共享變量或回調(diào)傳遞執(zhí)行狀態(tài)

通過(guò)在線程間共享對(duì)象,可以傳遞執(zhí)行狀態(tài)信息:

class TaskResult {
    private volatile boolean success = false;
    private volatile String message = "";
    private volatile Exception exception = null;
    private volatile boolean completed = false; // 增加完成標(biāo)記

    // 使用synchronized保證設(shè)置結(jié)果的原子性
    public synchronized void setSuccess(String message) {
        if (!completed) { // 避免重復(fù)設(shè)置
            this.success = true;
            this.message = message;
            this.completed = true;
        }
    }

    public synchronized void setFailure(Exception e, String message) {
        if (!completed) { // 避免重復(fù)設(shè)置
            this.success = false;
            this.exception = e;
            this.message = message;
            this.completed = true;
        }
    }

    public boolean isSuccess() {
        return success;
    }

    public boolean isCompleted() {
        return completed;
    }

    public String getMessage() {
        return message;
    }

    public Exception getException() {
        return exception;
    }
}

public class SharedObjectExample {
    public static void main(String[] args) {
        // 創(chuàng)建共享結(jié)果對(duì)象
        TaskResult result = new TaskResult();

        Thread thread = new Thread(() -> {
            try {
                System.out.println("工作線程開始執(zhí)行");
                // 模擬任務(wù)執(zhí)行
                Thread.sleep(2000);

                // 設(shè)置執(zhí)行成功
                result.setSuccess("任務(wù)順利完成");
            } catch (InterruptedException e) {
                result.setFailure(e, "線程被中斷");
                Thread.currentThread().interrupt();
            } catch (Exception e) {
                result.setFailure(e, "執(zhí)行異常:" + e.getMessage());
            }
        });

        try {
            thread.start();
            thread.join(); // 等待工作線程執(zhí)行完成

            // 檢查執(zhí)行結(jié)果
            if (!result.isCompleted()) {
                System.out.println("任務(wù)尚未完成");
            } else if (result.isSuccess()) {
                System.out.println("工作線程執(zhí)行成功:" + result.getMessage());
            } else {
                System.out.println("工作線程執(zhí)行失?。? + result.getMessage());
                if (result.getException() != null) {
                    System.out.println("異常信息:" + result.getException().toString());
                }
            }
        } catch (InterruptedException e) {
            System.err.println("主線程等待過(guò)程中被中斷");
            Thread.currentThread().interrupt();
        }
    }
}

優(yōu)點(diǎn)

  • 可以傳遞更詳細(xì)的執(zhí)行結(jié)果和異常信息
  • 適用于簡(jiǎn)單的線程狀態(tài)監(jiān)控

缺點(diǎn)

  • 需要自行處理線程安全問(wèn)題
  • 代碼結(jié)構(gòu)較為松散
  • 擴(kuò)展多個(gè)線程時(shí)較為復(fù)雜

方法三:使用 Future 和 Callable 獲取執(zhí)行結(jié)果和異常

Java 5 引入的 Future 接口提供了更優(yōu)雅的異步任務(wù)處理方式:

import java.util.concurrent.*;

public class FutureExample {
    public static void main(String[] args) {
        // 避免使用Executors工廠方法,直接配置ThreadPoolExecutor
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            1, // 核心線程數(shù)
            1, // 最大線程數(shù)
            0L, TimeUnit.MILLISECONDS, // 空閑線程保留時(shí)間
            new LinkedBlockingQueue<>(10), // 有界隊(duì)列,防止OOM
            new ThreadPoolExecutor.CallerRunsPolicy() // 拒絕策略
        );

        // 創(chuàng)建Callable任務(wù)
        Callable<String> task = () -> {
            System.out.println("工作線程開始執(zhí)行");
            // 模擬任務(wù)執(zhí)行
            Thread.sleep(2000);
            // 任務(wù)可以有返回值
            return "任務(wù)執(zhí)行結(jié)果";

            // 如果任務(wù)失敗,直接拋出異常
            // throw new RuntimeException("任務(wù)執(zhí)行失敗");
        };

        // 提交任務(wù)并獲取Future
        Future<String> future = executor.submit(task);

        try {
            // 等待任務(wù)完成并獲取結(jié)果,可以設(shè)置超時(shí)
            String result = future.get(3, TimeUnit.SECONDS);
            System.out.println("工作線程執(zhí)行成功,結(jié)果:" + result);
        } catch (TimeoutException e) {
            System.err.println("任務(wù)執(zhí)行超時(shí)");
            future.cancel(true); // 嘗試取消任務(wù)
        } catch (ExecutionException e) {
            System.err.println("任務(wù)執(zhí)行異常:" + e.getCause().getMessage());
            // getCause()獲取任務(wù)中拋出的原始異常
        } catch (InterruptedException e) {
            System.err.println("主線程等待過(guò)程中被中斷");
            Thread.currentThread().interrupt();
        } finally {
            // 記得關(guān)閉線程池
            executor.shutdown();
        }
    }
}

優(yōu)點(diǎn)

  • 可以獲取線程執(zhí)行結(jié)果或異常
  • 支持超時(shí)設(shè)置
  • 可以取消任務(wù)執(zhí)行

使用 Future 處理多個(gè)任務(wù)

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class MultipleFuturesExample {
    public static void main(String[] args) {
        // 創(chuàng)建線程池 - 根據(jù)任務(wù)類型配置參數(shù)
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            3, // 核心線程數(shù) - 根據(jù)任務(wù)特性選擇
            3, // 最大線程數(shù)
            60L, TimeUnit.SECONDS, // 空閑線程保留時(shí)間
            new ArrayBlockingQueue<>(10), // 有界隊(duì)列,避免OOM
            new ThreadPoolExecutor.AbortPolicy() // 任務(wù)拒絕時(shí)拋出異常
        );

        // 創(chuàng)建多個(gè)任務(wù)
        List<Callable<String>> tasks = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            final int taskId = i;
            tasks.add(() -> {
                System.out.println("任務(wù)" + taskId + "開始執(zhí)行");
                // 模擬不同執(zhí)行時(shí)間
                Thread.sleep(1000 + taskId * 1000);

                // 模擬可能的失敗
                if (taskId == 1) {
                    throw new RuntimeException("任務(wù)" + taskId + "執(zhí)行失敗");
                }

                return "任務(wù)" + taskId + "執(zhí)行結(jié)果";
            });
        }

        try {
            // 提交所有任務(wù)并獲取Future列表
            List<Future<String>> futures = executor.invokeAll(tasks);

            // 處理每個(gè)任務(wù)的結(jié)果 - 確保一個(gè)任務(wù)的異常不會(huì)影響其他任務(wù)處理
            for (int i = 0; i < futures.size(); i++) {
                Future<String> future = futures.get(i);
                try {
                    // 檢查任務(wù)是否被取消
                    if (future.isCancelled()) {
                        System.err.println("任務(wù)" + i + "被取消");
                        continue;
                    }

                    String result = future.get();
                    System.out.println("任務(wù)" + i + "執(zhí)行成功:" + result);
                } catch (ExecutionException e) {
                    System.err.println("任務(wù)" + i + "執(zhí)行異常:" + e.getCause().getMessage());
                } catch (CancellationException e) {
                    System.err.println("任務(wù)" + i + "被取消");
                }
            }
        } catch (InterruptedException e) {
            System.err.println("主線程等待過(guò)程中被中斷");
            Thread.currentThread().interrupt();
        } finally {
            // 關(guān)閉線程池
            shutdownAndAwaitTermination(executor);
        }
    }

    // 安全關(guān)閉線程池的標(biāo)準(zhǔn)方法
    private static void shutdownAndAwaitTermination(ExecutorService pool) {
        pool.shutdown();
        try {
            if (!pool.awaitTermination(5, TimeUnit.SECONDS)) {
                pool.shutdownNow();
                if (!pool.awaitTermination(5, TimeUnit.SECONDS)) {
                    System.err.println("線程池?zé)o法終止");
                }
            }
        } catch (InterruptedException e) {
            pool.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
}

線程池拒絕策略的選擇依據(jù)

在配置線程池時(shí),選擇合適的拒絕策略非常重要:

  • CallerRunsPolicy:將任務(wù)回退到調(diào)用者線程執(zhí)行。當(dāng)系統(tǒng)負(fù)載過(guò)高時(shí),能起到自動(dòng)降速的作用,因?yàn)樘峤蝗蝿?wù)的線程會(huì)被迫自己執(zhí)行任務(wù),暫時(shí)無(wú)法提交新任務(wù)。適用于不能丟棄任務(wù)且需要自動(dòng)調(diào)節(jié)提交速率的場(chǎng)景。

  • AbortPolicy:直接拋出 RejectedExecutionException 異常。適用于需要明確知道任務(wù)被拒絕并進(jìn)行特殊處理的場(chǎng)景,比如重要業(yè)務(wù)任務(wù)。

  • DiscardPolicy:靜默丟棄任務(wù),不做任何處理。適用于任務(wù)可以安全丟棄且無(wú)需通知的場(chǎng)景,如統(tǒng)計(jì)類非關(guān)鍵任務(wù)。

  • DiscardOldestPolicy:丟棄隊(duì)列中等待最久的任務(wù),然后嘗試重新提交當(dāng)前任務(wù)。適用于新任務(wù)比舊任務(wù)更重要的場(chǎng)景,如實(shí)時(shí)監(jiān)控?cái)?shù)據(jù)。

// 選擇示例
// 1. 關(guān)鍵業(yè)務(wù)任務(wù) - 不能丟失,需要感知拒絕
new ThreadPoolExecutor(cores, maxThreads, keepAliveTime,
    timeUnit, queue, new ThreadPoolExecutor.AbortPolicy());

// 2. 高負(fù)載任務(wù) - 防止系統(tǒng)崩潰,允許降速
new ThreadPoolExecutor(cores, maxThreads, keepAliveTime,
    timeUnit, queue, new ThreadPoolExecutor.CallerRunsPolicy());

// 3. 非關(guān)鍵統(tǒng)計(jì)任務(wù) - 可以安全丟棄
new ThreadPoolExecutor(cores, maxThreads, keepAliveTime,
    timeUnit, queue, new ThreadPoolExecutor.DiscardPolicy());

方法四:使用 CompletableFuture 實(shí)現(xiàn)異步任務(wù)監(jiān)控

Java 8 引入的 CompletableFuture 提供了更強(qiáng)大的異步編程能力,特別適合復(fù)雜的任務(wù)依賴場(chǎng)景:

import java.util.concurrent.*;
import java.util.function.Supplier;

public class CompletableFutureExample {
    public static void main(String[] args) {
        // 創(chuàng)建線程池 - 適合IO密集型任務(wù)的線程池配置
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors() * 2, // IO密集型任務(wù)可使用更多線程
            Runtime.getRuntime().availableProcessors() * 2,
            60L, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(100),
            new ThreadFactory() {
                @Override
                public Thread newThread(Runnable r) {
                    Thread t = new Thread(r, "async-task-" + System.currentTimeMillis());
                    t.setDaemon(false); // 非守護(hù)線程
                    return t;
                }
            }
        );

        // 創(chuàng)建任務(wù)
        Supplier<String> task = () -> {
            try {
                System.out.println("工作線程開始執(zhí)行,ID:" + Thread.currentThread().getId());
                // 模擬任務(wù)執(zhí)行
                Thread.sleep(2000);

                // 模擬可能的異常
                if (Math.random() < 0.3) {
                    throw new RuntimeException("任務(wù)隨機(jī)失敗");
                }

                return "任務(wù)執(zhí)行結(jié)果";
            } catch (InterruptedException e) {
                // 保留完整的異常棧信息
                Thread.currentThread().interrupt();
                throw new IllegalStateException("任務(wù)被中斷", e); // 使用標(biāo)準(zhǔn)異常
            }
        };

        // 創(chuàng)建CompletableFuture并指定執(zhí)行線程池
        CompletableFuture<String> future = CompletableFuture
            .supplyAsync(task, executor)
            .thenApply(result -> {
                // 對(duì)結(jié)果進(jìn)行處理 - 默認(rèn)在任務(wù)線程執(zhí)行
                return "處理后的" + result;
            })
            .exceptionally(ex -> {
                // 異常處理
                System.err.println("任務(wù)異常:" + ex.getCause().getMessage());
                return "默認(rèn)結(jié)果";
            });

        // 添加完成回調(diào) - 確?;卣{(diào)在主線程執(zhí)行
        ExecutorService callbackExecutor = Executors.newSingleThreadExecutor();
        future.whenCompleteAsync((result, ex) -> {
            if (ex == null) {
                System.out.println("任務(wù)完成,結(jié)果:" + result);
            } else {
                System.err.println("任務(wù)異常:" + ex.getMessage());
            }
        }, callbackExecutor);

        try {
            // 等待任務(wù)完成
            String result = future.get(5, TimeUnit.SECONDS);
            System.out.println("最終結(jié)果:" + result);
        } catch (Exception e) {
            System.err.println("獲取結(jié)果異常:" + e.getMessage());
        } finally {
            // 關(guān)閉線程池
            shutdownAndAwaitTermination(executor);
            shutdownAndAwaitTermination(callbackExecutor);
        }
    }

    // 安全關(guān)閉線程池的標(biāo)準(zhǔn)方法
    private static void shutdownAndAwaitTermination(ExecutorService pool) {
        pool.shutdown();
        try {
            if (!pool.awaitTermination(5, TimeUnit.SECONDS)) {
                pool.shutdownNow();
                if (!pool.awaitTermination(5, TimeUnit.SECONDS)) {
                    System.err.println("線程池?zé)o法終止");
                }
            }
        } catch (InterruptedException e) {
            pool.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
}

CompletableFuture 多級(jí)異常處理

CompletableFuture 的一大強(qiáng)項(xiàng)是處理復(fù)雜的任務(wù)鏈,下面是處理多級(jí)異常的示例:

public void processWithErrorHandling() {
    CompletableFuture<String> future = CompletableFuture
        .supplyAsync(() -> {
            // 步驟1:獲取原始數(shù)據(jù)
            if (Math.random() < 0.2) {
                throw new RuntimeException("獲取數(shù)據(jù)失敗");
            }
            return "原始數(shù)據(jù)";
        })
        .thenApply(data -> {
            // 步驟2:處理數(shù)據(jù)
            if (data.contains("錯(cuò)誤")) {
                throw new IllegalArgumentException("數(shù)據(jù)格式錯(cuò)誤");
            }
            return data + "已處理";
        })
        .thenApply(processed -> {
            // 步驟3:格式化結(jié)果
            if (Math.random() < 0.1) {
                throw new RuntimeException("格式化失敗");
            }
            return "[" + processed + "]";
        })
        .exceptionally(ex -> {
            // 捕獲任何步驟的異常
            Throwable cause = ex.getCause() != null ? ex.getCause() : ex;
            log.error("處理鏈異常: {}", cause.getMessage());

            // 根據(jù)異常類型返回不同的默認(rèn)值
            if (cause instanceof IllegalArgumentException) {
                return "[格式錯(cuò)誤默認(rèn)值]";
            }
            return "[系統(tǒng)錯(cuò)誤默認(rèn)值]";
        });

    // 還可以添加完成回調(diào)處理最終結(jié)果
    future.whenComplete((result, ex) -> {
        if (ex == null) {
            System.out.println("處理完成: " + result);
        } else {
            System.err.println("處理失敗: " + ex.getMessage());
            // 注意:此處不能返回新值
        }
    });
}

exceptionally 與 whenComplete 對(duì)比

  • exceptionally: 可以恢復(fù)異常并返回替代結(jié)果。用于類似 try-catch-return 的場(chǎng)景。
  • whenComplete: 無(wú)法修改結(jié)果,只能執(zhí)行最終操作。類似 finally 塊,常用于日志記錄或監(jiān)控。

多個(gè)異常處理器可以組合使用,形成精細(xì)的異常處理鏈:

CompletableFuture<String> future = CompletableFuture
    .supplyAsync(this::fetchData)
    .exceptionally(ex -> {
        // 處理fetchData階段異常
        log.warn("數(shù)據(jù)獲取失敗,使用緩存數(shù)據(jù)");
        return getCachedData();
    })
    .thenApply(this::processData)
    .exceptionally(ex -> {
        // 處理processData階段異常
        log.warn("數(shù)據(jù)處理失敗,使用簡(jiǎn)化處理");
        return getSimpleProcessing();
    });

組合多個(gè) CompletableFuture

import java.util.concurrent.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.List;

public class MultipleCompletableFuturesExample {
    public static void main(String[] args) {
        // 創(chuàng)建自定義線程池 - CPU密集型任務(wù)配置
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors(), // CPU密集型任務(wù)核心線程數(shù)=CPU核數(shù)
            Runtime.getRuntime().availableProcessors(),
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>()
        );

        try {
            // 創(chuàng)建多個(gè)CompletableFuture任務(wù)
            List<CompletableFuture<String>> futures = IntStream.range(0, 5)
                .mapToObj(i -> CompletableFuture.supplyAsync(() -> {
                    try {
                        System.out.println("任務(wù)" + i + "開始執(zhí)行");
                        Thread.sleep(1000 + i * 500);
                        // 模擬可能的失敗
                        if (i == 2) {
                            throw new RuntimeException("任務(wù)" + i + "執(zhí)行失敗");
                        }
                        return "任務(wù)" + i + "執(zhí)行成功";
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        // 直接拋出原始異常,CompletableFuture會(huì)自動(dòng)包裝
                        throw new IllegalStateException("任務(wù)中斷", e);
                    }
                }, executor)
                .exceptionally(ex -> "任務(wù)異常:" + ex.getCause().getMessage()))
                .collect(Collectors.toList());

            // 等待所有任務(wù)完成
            CompletableFuture<Void> allFutures = CompletableFuture.allOf(
                futures.toArray(new CompletableFuture[0])
            );

            // 設(shè)置超時(shí)
            try {
                allFutures.get(10, TimeUnit.SECONDS);
            } catch (TimeoutException e) {
                System.err.println("部分任務(wù)執(zhí)行超時(shí)");
            }

            // 使用Stream API簡(jiǎn)化結(jié)果收集 - 替代原來(lái)的循環(huán)
            List<String> results = futures.stream()
                .map(future -> {
                    if (future.isDone() && !future.isCancelled() && !future.isCompletedExceptionally()) {
                        try {
                            return future.getNow("任務(wù)未完成");
                        } catch (Exception e) {
                            return "獲取結(jié)果異常:" + e.getMessage();
                        }
                    } else if (future.isCancelled()) {
                        return "任務(wù)已被取消";
                    } else if (future.isCompletedExceptionally()) {
                        return "任務(wù)異常完成";
                    } else {
                        return "任務(wù)未完成";
                    }
                })
                .collect(Collectors.toList());

            // 打印所有結(jié)果
            System.out.println("所有任務(wù)執(zhí)行結(jié)果:");
            for (int i = 0; i < results.size(); i++) {
                System.out.println(i + ": " + results.get(i));
            }

        } catch (Exception e) {
            System.err.println("主線程異常:" + e.getMessage());
        } finally {
            executor.shutdown();
        }
    }
}

CompletableFuture 優(yōu)點(diǎn)

  • 支持任務(wù)組合和鏈?zhǔn)秸{(diào)用(如流水線、并行執(zhí)行)
  • 更靈活的異常處理機(jī)制
  • 可添加任務(wù)完成回調(diào)
  • 支持多任務(wù)協(xié)調(diào)(allOf、anyOf 等)

Future 與 CompletableFuture 的關(guān)鍵區(qū)別

Future.get() vs Future.getNow()

  • get(): 阻塞方法,會(huì)等待任務(wù)完成或超時(shí)
  • getNow(defaultValue): 非阻塞方法,若任務(wù)未完成立即返回默認(rèn)值

CompletableFuture 的線程模型

  • 默認(rèn)使用ForkJoinPool.commonPool(),適合計(jì)算密集型任務(wù)
  • 自定義線程池的最佳實(shí)踐:
    • IO 密集型任務(wù):線程數(shù) = CPU 核心數(shù) * (1 + 平均等待時(shí)間/平均計(jì)算時(shí)間)
    • CPU 密集型任務(wù):線程數(shù) = CPU 核心數(shù) + 1
    • 總是使用有界隊(duì)列防止 OOM
    • 明確設(shè)置拒絕策略

線程池泄漏風(fēng)險(xiǎn)

  • 未正確關(guān)閉線程池會(huì)導(dǎo)致應(yīng)用無(wú)法正常退出
  • 生產(chǎn)環(huán)境必須使用try-finally模式確保線程池關(guān)閉

使用 UncaughtExceptionHandler 捕獲線程未處理異常

對(duì)于直接使用 Thread 的場(chǎng)景,可以設(shè)置 UncaughtExceptionHandler 來(lái)捕獲線程中未被捕獲的異常:

public class ExceptionHandlerExample {
    public static void main(String[] args) {
        // 設(shè)置默認(rèn)的未捕獲異常處理器
        Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
            System.err.println("線程" + thread.getName() + "發(fā)生未捕獲異常:" + throwable.getMessage());
        });

        // 創(chuàng)建并啟動(dòng)可能拋出異常的線程
        Thread thread = new Thread(() -> {
            System.out.println("工作線程開始執(zhí)行");
            // 模擬未捕獲的異常
            throw new RuntimeException("發(fā)生了一個(gè)未處理的異常");
        });

        // 也可以為單個(gè)線程設(shè)置異常處理器
        thread.setUncaughtExceptionHandler((t, e) -> {
            System.err.println("線程" + t.getName() + "的專屬異常處理器捕獲到異常:" + e.getMessage());
        });

        thread.start();

        try {
            // 讓主線程等待一會(huì),確保能看到異常處理結(jié)果
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

注意:UncaughtExceptionHandler 只能捕獲線程中未被 try-catch 處理的異常,主要用于記錄異常信息,且無(wú)法區(qū)分任務(wù)是成功還是主動(dòng)失敗(如返回錯(cuò)誤碼)。特別說(shuō)明,只有未檢查異常(RuntimeException 及其子類)才會(huì)觸發(fā)該處理器,受檢異常必須在代碼中顯式處理。

線程池配置最佳實(shí)踐

根據(jù)任務(wù)類型選擇合適的線程池配置至關(guān)重要:

// CPU密集型任務(wù)線程池 - 線程數(shù)接近CPU核心數(shù)
ExecutorService cpuIntensivePool = new ThreadPoolExecutor(
    Runtime.getRuntime().availableProcessors(),
    Runtime.getRuntime().availableProcessors(),
    0L, TimeUnit.MILLISECONDS,
    new LinkedBlockingQueue<>(1000), // 合理大小的隊(duì)列
    new ThreadPoolExecutor.CallerRunsPolicy() // 避免任務(wù)丟失
);

// IO密集型任務(wù)線程池 - 更多的線程數(shù)應(yīng)對(duì)IO等待
ExecutorService ioIntensivePool = new ThreadPoolExecutor(
    Runtime.getRuntime().availableProcessors() * 2,
    Runtime.getRuntime().availableProcessors() * 4,
    60L, TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(1000),
    new ThreadPoolExecutor.AbortPolicy() // 隊(duì)列滿時(shí)拒絕新任務(wù)
);

避開 Executors 工廠方法的原因

  • newFixedThreadPoolnewSingleThreadExecutor 使用無(wú)界隊(duì)列(LinkedBlockingQueue),可能導(dǎo)致 OOM
  • newCachedThreadPool 允許創(chuàng)建無(wú)限線程,可能導(dǎo)致 OOM
  • newScheduledThreadPool 同樣允許無(wú)限任務(wù)堆積

實(shí)際場(chǎng)景示例

以下是一個(gè)在實(shí)際項(xiàng)目中常見的 Web 后臺(tái)任務(wù)監(jiān)控示例:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Collectors;

public class WebBackgroundTasksExample {

    // 模擬數(shù)據(jù)處理服務(wù)
    static class DataProcessingService {
        public List<String> processLargeData(List<String> data) {
            // 創(chuàng)建線程池 - 根據(jù)任務(wù)特性選擇合適配置
            ThreadPoolExecutor executor = new ThreadPoolExecutor(
                Math.min(data.size(), Runtime.getRuntime().availableProcessors() * 2),
                Math.min(data.size(), Runtime.getRuntime().availableProcessors() * 2),
                0L, TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<>(Math.max(10, data.size())), // 有界隊(duì)列
                new ThreadFactory() {
                    @Override
                    public Thread newThread(Runnable r) {
                        Thread t = new Thread(r, "data-processor-" + System.currentTimeMillis());
                        t.setUncaughtExceptionHandler((thread, ex) ->
                            System.err.println("線程" + thread.getName() + "未捕獲異常: " + ex.getMessage())
                        );
                        return t;
                    }
                },
                new ThreadPoolExecutor.CallerRunsPolicy() // 拒絕策略
            );

            try {
                // 為每條數(shù)據(jù)創(chuàng)建處理任務(wù)
                List<CompletableFuture<String>> futures = data.stream()
                    .map(item -> CompletableFuture.supplyAsync(() -> {
                        try {
                            // 模擬復(fù)雜處理
                            if (item.contains("error")) {
                                throw new RuntimeException("處理數(shù)據(jù)項(xiàng) '" + item + "' 時(shí)出錯(cuò)");
                            }
                            Thread.sleep(500); // 模擬處理時(shí)間
                            return item.toUpperCase(); // 處理結(jié)果
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            throw new IllegalStateException("處理被中斷", e);
                        }
                    }, executor)
                    .exceptionally(ex -> {
                        // 記錄錯(cuò)誤,但允許繼續(xù)處理其他數(shù)據(jù)
                        System.err.println("數(shù)據(jù)處理異常: " + ex.getMessage());
                        return "ERROR_" + item;
                    }))
                    .collect(Collectors.toList());

                // 等待所有任務(wù)完成,但最多等待10秒
                CompletableFuture<Void> allFutures = CompletableFuture.allOf(
                    futures.toArray(new CompletableFuture[0])
                );

                try {
                    allFutures.get(10, TimeUnit.SECONDS);
                } catch (TimeoutException e) {
                    System.err.println("處理超時(shí),將返回已完成部分的結(jié)果");
                }

                // 使用Stream API收集結(jié)果
                return IntStream.range(0, data.size())
                    .mapToObj(i -> {
                        CompletableFuture<String> future = futures.get(i);
                        String item = data.get(i);

                        if (future.isDone() && !future.isCompletedExceptionally() && !future.isCancelled()) {
                            try {
                                return future.getNow("處理失敗");
                            } catch (Exception e) {
                                return "處理出錯(cuò): " + e.getMessage();
                            }
                        } else if (future.isCancelled()) {
                            return item + "_已取消";
                        } else if (future.isCompletedExceptionally()) {
                            return item + "_異常完成";
                        } else {
                            return item + "_處理未完成";
                        }
                    })
                    .collect(Collectors.toList());

            } finally {
                // 確保關(guān)閉線程池
                shutdownAndAwaitTermination(executor);
            }
        }

        // 安全關(guān)閉線程池的標(biāo)準(zhǔn)方法
        private void shutdownAndAwaitTermination(ExecutorService pool) {
            pool.shutdown();
            try {
                if (!pool.awaitTermination(5, TimeUnit.SECONDS)) {
                    pool.shutdownNow();
                    if (!pool.awaitTermination(5, TimeUnit.SECONDS)) {
                        System.err.println("線程池?zé)o法終止");
                    }
                }
            } catch (InterruptedException e) {
                pool.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
    }

    public static void main(String[] args) {
        // 準(zhǔn)備測(cè)試數(shù)據(jù)
        List<String> testData = new ArrayList<>();
        testData.add("item1");
        testData.add("error_item");
        testData.add("item3");
        testData.add("item4");
        testData.add("another_error");

        // 處理數(shù)據(jù)
        DataProcessingService service = new DataProcessingService();
        List<String> results = service.processLargeData(testData);

        // 輸出結(jié)果
        System.out.println("處理結(jié)果:");
        for (int i = 0; i < results.size(); i++) {
            System.out.println(testData.get(i) + " -> " + results.get(i));
        }
    }
}

總結(jié)

方法支持返回值異常處理方式任務(wù)組合能力異步回調(diào)支持線程池集成度支持超時(shí)支持任務(wù)取消適用場(chǎng)景
Thread.join()無(wú)(需共享變量)僅順序等待是(基礎(chǔ))簡(jiǎn)單等待工作線程完成
共享變量/對(duì)象是(手動(dòng))手動(dòng)設(shè)置異常狀態(tài)復(fù)雜否(除非配合 join)簡(jiǎn)單的狀態(tài)傳遞
Future/Callableget()拋出異常有限(需批量處理)高(線程池)是(cancel())需要獲取執(zhí)行結(jié)果和異常
CompletableFutureexceptionally 鏈?zhǔn)?/td>強(qiáng)(allOf/anyOf)是(回調(diào))復(fù)雜的任務(wù)鏈和依賴關(guān)系
UncaughtExceptionHandler僅捕獲未檢查異常無(wú)有限全局異常監(jiān)控

在實(shí)際開發(fā)中,根據(jù)業(yè)務(wù)場(chǎng)景的復(fù)雜度和需求選擇合適的方法。對(duì)于簡(jiǎn)單任務(wù),Thread.join()或共享變量就足夠了;對(duì)于需要返回值和異常處理的場(chǎng)景,F(xiàn)uture/Callable 是不錯(cuò)的選擇;而對(duì)于復(fù)雜任務(wù)鏈和依賴關(guān)系,CompletableFuture 則是最佳方案。無(wú)論選擇哪種方式,都要確保正確處理異常、設(shè)置合理超時(shí),并妥善管理線程資源。

以上就是Java中線程執(zhí)行狀態(tài)檢測(cè)的四種可靠方法的詳細(xì)內(nèi)容,更多關(guān)于Java線程執(zhí)行狀態(tài)檢測(cè)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java JSON解析庫(kù)Alibaba Fastjson用法詳解

    java JSON解析庫(kù)Alibaba Fastjson用法詳解

    這篇文章主要介紹了java JSON解析庫(kù)Alibaba Fastjson用法,結(jié)合實(shí)例形式詳細(xì)分析了java JSON解析庫(kù)Alibaba Fastjson的基本功能、原理、用法及操作注意事項(xiàng),需要的朋友可以參考下
    2020-04-04
  • Java stringBuilder的使用方法及實(shí)例解析

    Java stringBuilder的使用方法及實(shí)例解析

    這篇文章主要介紹了Java stringBuilder的使用方法及實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • Myeclipse 2016下Aptana安裝教程

    Myeclipse 2016下Aptana安裝教程

    這篇文章主要為大家詳細(xì)介紹了Myeclipse 2016下Aptana安裝教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • 淺談?dòng)肧pringBoot實(shí)現(xiàn)策略模式

    淺談?dòng)肧pringBoot實(shí)現(xiàn)策略模式

    本文主要介紹了SpringBoot實(shí)現(xiàn)策略模式,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • java必學(xué)必會(huì)之GUI編程

    java必學(xué)必會(huì)之GUI編程

    這篇文章主要為大家詳細(xì)介紹了java GUI編程,對(duì)于GUI編程小編也不是很了解,通過(guò)這篇文章和大家一起學(xué)習(xí)GUI編程,感興趣的小伙伴們可以參考一下
    2015-12-12
  • Mybatis設(shè)置sql打印日志的多種方法

    Mybatis設(shè)置sql打印日志的多種方法

    這篇文章主要介紹了Mybatis設(shè)置sql打印日志,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-08-08
  • SWT JFace 拖曳效果

    SWT JFace 拖曳效果

    SWT(JFace)體驗(yàn)之拖曳效果
    2009-06-06
  • Jmeter解析返回參數(shù)以及解析并操作json方式

    Jmeter解析返回參數(shù)以及解析并操作json方式

    本文總結(jié)了Java或JMeter的BeanShell腳本中處理JSON字符串的常用操作,包括解析JSON數(shù)組、JSON對(duì)象和嵌套的JSON字符串,并提供了示例代碼和打印結(jié)果
    2025-02-02
  • Spring?Security過(guò)濾器鏈體系的實(shí)例詳解

    Spring?Security過(guò)濾器鏈體系的實(shí)例詳解

    這篇文章主要介紹了Spring?Security過(guò)濾器鏈體系,通過(guò)思維導(dǎo)圖可以很好的幫助大家理解配置類的相關(guān)知識(shí),結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-02-02
  • 解決Mybatis?plus實(shí)體類屬性與表字段不一致的問(wèn)題

    解決Mybatis?plus實(shí)體類屬性與表字段不一致的問(wèn)題

    這篇文章主要介紹了Mybatis?plus實(shí)體類屬性與表字段不一致解決方法,文末給大家提到了Mybatis-plus中數(shù)據(jù)庫(kù)表名和表字段名的相關(guān)知識(shí),需要的朋友可以參考下
    2022-07-07

最新評(píng)論

胶州市| 石狮市| 邵武市| 噶尔县| 涞水县| 巫溪县| 邳州市| 扎赉特旗| 西青区| 遂平县| 保山市| 和政县| 西畴县| 马尔康县| 佛学| 类乌齐县| 乐至县| 竹山县| 罗甸县| 博罗县| 哈密市| 新干县| 宁强县| 庄河市| 镇雄县| 南丹县| 马龙县| 丰都县| 泸定县| 张掖市| 伊川县| 佛冈县| 乐东| 闵行区| 嘉鱼县| 昌宁县| 陵水| 广河县| 阳江市| 嘉禾县| 隆回县|