面试题:在 Java 中主线程如何知晓创建的子线程是否执行成功?

在 Java 中,主线程可以通过多种方式知晓创建的子线程是否执行成功。以下是几种常见的实现方式:


1. 使用 Thread.join() 方法

  • 作用:主线程调用子线程的 join() 方法,等待子线程执行完毕。
  • 实现
    • 主线程调用 join() 后,会阻塞直到子线程执行完成。
    • 可以通过子线程的返回值或状态判断是否执行成功。

示例

public class JoinExample {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            System.out.println("子线程开始执行");
            try {
                Thread.sleep(1000); // 模拟耗时操作
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("子线程执行完毕");
        });

        thread.start();
        thread.join(); // 主线程等待子线程执行完毕
        System.out.println("主线程知晓子线程执行完毕");
    }
}

2. 使用 Future 和 Callable

  • 作用:通过 ExecutorService 提交一个 Callable 任务,返回一个 Future 对象。
  • 实现
    • 主线程可以通过 Future.get() 方法获取子线程的执行结果。
    • 如果子线程执行成功,Future.get() 会返回结果;如果子线程抛出异常,Future.get() 会抛出 ExecutionException

示例

import java.util.concurrent.*;

public class FutureExample {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<String> future = executor.submit(() -> {
            System.out.println("子线程开始执行");
            Thread.sleep(1000); // 模拟耗时操作
            System.out.println("子线程执行完毕");
            return "执行成功";
        });

        String result = future.get(); // 主线程获取子线程的执行结果
        System.out.println("子线程执行结果: " + result);
        executor.shutdown();
    }
}

3. 使用 CompletableFuture

  • 作用CompletableFuture 是 Java 8 引入的增强版 Future,支持更灵活的异步编程。
  • 实现
    • 主线程可以通过 CompletableFuture 的回调方法(如 thenAcceptexceptionally)处理子线程的执行结果或异常。

示例

import java.util.concurrent.CompletableFuture;

public class CompletableFutureExample {
    public static void main(String[] args) {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("子线程开始执行");
            try {
                Thread.sleep(1000); // 模拟耗时操作
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("子线程执行完毕");
            return "执行成功";
        });

        future.thenAccept(result -> {
            System.out.println("子线程执行结果: " + result);
        }).exceptionally(ex -> {
            System.out.println("子线程执行失败: " + ex.getMessage());
            return null;
        });

        // 主线程继续执行其他任务
        System.out.println("主线程继续执行");
    }
}

4. 使用共享变量

  • 作用:通过共享变量(如 volatile 变量或原子类)传递子线程的执行状态。
  • 实现
    • 子线程执行完成后,更新共享变量的状态。
    • 主线程通过轮询或等待共享变量的状态变化来判断子线程是否执行成功。

示例

public class SharedVariableExample {
    private static volatile boolean isSuccess = false;

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            System.out.println("子线程开始执行");
            try {
                Thread.sleep(1000); // 模拟耗时操作
                isSuccess = true; // 子线程执行成功
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("子线程执行完毕");
        });

        thread.start();
        while (!isSuccess) {
            Thread.sleep(100); // 主线程等待子线程执行成功
        }
        System.out.println("主线程知晓子线程执行成功");
    }
}

5. 使用 CountDownLatch

  • 作用CountDownLatch 是一个同步工具,用于等待一个或多个线程完成。
  • 实现
    • 主线程通过 CountDownLatch.await() 等待子线程执行完成。
    • 子线程执行完成后,调用 CountDownLatch.countDown() 通知主线程。

示例

import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(1);

        Thread thread = new Thread(() -> {
            System.out.println("子线程开始执行");
            try {
                Thread.sleep(1000); // 模拟耗时操作
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("子线程执行完毕");
            latch.countDown(); // 通知主线程
        });

        thread.start();
        latch.await(); // 主线程等待子线程执行完毕
        System.out.println("主线程知晓子线程执行完毕");
    }
}

6. 总结

方法优点缺点适用场景
Thread.join()简单易用主线程会阻塞简单的线程等待场景
Future 和 Callable支持返回值,异常处理需要线程池,主线程会阻塞需要获取执行结果的场景
CompletableFuture支持回调,灵活性高需要理解异步编程模型复杂的异步编程场景
共享变量简单需要轮询,可能浪费 CPU 资源简单的状态共享场景
CountDownLatch支持多个线程同步需要额外的同步工具多线程协同场景

根据具体需求选择合适的方式,主线程可以有效地知晓子线程是否执行成功。

THE END
点赞7 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容