MST

星途 面试题库

面试题:Java函数式接口与并发编程结合的复杂场景处理

在多线程环境下,有多个任务需要执行,每个任务接受一个整数参数并返回一个字符串结果。这些任务需要使用函数式接口定义,然后通过线程池并发执行,最后将所有结果收集到一个List<String>中并返回。请编写完整的Java代码实现该功能,并详细说明如何处理线程安全问题以及函数式接口在此场景中的优势。
41.3万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Collectors;

// 定义函数式接口
@FunctionalInterface
interface Task {
    String execute(int param);
}

public class MultiThreadTaskExecutor {

    public static List<String> executeTasks(List<Integer> params) {
        // 创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        List<Future<String>> futures = new ArrayList<>();

        // 提交任务到线程池
        for (int param : params) {
            Task task = (p) -> {
                // 模拟任务执行
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                return "Result for param " + p;
            };
            futures.add(executorService.submit(() -> task.execute(param)));
        }

        // 关闭线程池
        executorService.shutdown();

        // 收集结果
        List<String> results = new ArrayList<>();
        for (Future<String> future : futures) {
            try {
                results.add(future.get());
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }

        return results;
    }

    public static void main(String[] args) {
        List<Integer> params = List.of(1, 2, 3, 4, 5);
        List<String> results = executeTasks(params);
        System.out.println(results);
    }
}

线程安全问题处理

  1. 线程池:使用ExecutorService创建线程池来管理线程,避免了线程的频繁创建和销毁。线程池本身是线程安全的,它会负责调度任务到不同的线程执行。
  2. 不可变数据:在任务执行过程中,尽量使用不可变数据。例如,任务接受的整数参数是不可变的,这样避免了多个线程对同一可变数据的竞争。
  3. 避免共享可变状态:在上述代码中,每个任务都是独立的,没有共享可变状态,从而减少了线程安全问题。如果确实需要共享状态,可以使用java.util.concurrent.atomic包中的原子类,或者使用ConcurrentHashMap等线程安全的集合类。

函数式接口在此场景中的优势

  1. 简洁性:函数式接口允许使用Lambda表达式来创建任务实例,代码更加简洁。例如,Task task = (p) -> {... },相比于传统的匿名内部类实现方式更加紧凑。
  2. 行为参数化:可以将不同的任务行为作为参数传递给方法。如果有不同类型的任务,只需要实现Task接口的execute方法,就可以方便地在同一线程池框架下执行。
  3. 更好的可读性:Lambda表达式能够清晰地表达任务的逻辑,使代码更易于理解和维护。特别是在处理简单任务时,Lambda表达式的语义非常直观。