返回

Callable、Future 和 Executor:深入剖析并发编程的基础

后端

深入理解 Callable、Future 和 Executor:解锁 Java 并发编程的强大功能

Callable:封装异步任务

想象一个 Callable,就像一个熟练的厨师,负责执行一个特定任务,然后返回精心制作的结果。它类似于 Runnable,但与 Runnable 不同的是,它在完成任务后会返回一个结果,就像厨师精心制作的菜肴。

Future:获取任务结果

Future 就好像一位耐心等待的侍者,它持有任务的结果,直到厨师准备好。它提供了一个 get() 方法,就像一位顾客要求上菜一样,Future 会阻塞并等待厨师完成任务,然后将结果呈上。

Executor:任务执行的指挥官

Executor 就像一位经验丰富的餐厅经理,它负责管理厨师(任务)和资源(线程)。当一个任务准备好被执行时,经理就会将其交给一个厨师(线程),厨师负责执行任务并返回结果。

构建我们自己的工具

为了真正理解这些概念,让我们亲自动手构建它们。

Callable:任务的蓝图

public class SumTask implements Callable<Integer> {

    private List<Integer> numbers;

    public SumTask(List<Integer> numbers) {
        this.numbers = numbers;
    }

    @Override
    public Integer call() {
        int sum = 0;
        for (int num : numbers) {
            sum += num;
        }
        return sum;
    }
}

Future:结果的容器

public class SumFuture implements Future<Integer> {

    private Integer result;
    private boolean isDone;

    public Integer get() {
        while (!isDone) {
            try {
                wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        return result;
    }

    public boolean isDone() {
        return isDone;
    }

    public boolean cancel(boolean mayInterruptIfRunning) {
        return false;
    }

    public void setResult(Integer result) {
        synchronized (this) {
            this.result = result;
            this.isDone = true;
            notifyAll();
        }
    }
}

Executor:任务的执行者

public class SimpleExecutor implements Executor {

    @Override
    public void execute(Runnable command) {
        new Thread(command).start();
    }
}

使用我们的工具

现在,我们有了自己的工具,让我们执行一个异步任务:

List<Integer> numbers = List.of(1, 2, 3, 4, 5);
SumTask task = new SumTask(numbers);
SumFuture future = new SumFuture();
SimpleExecutor executor = new SimpleExecutor();

executor.execute(task);
Integer result = future.get();

System.out.println("Sum of numbers: " + result);

这个代码就像一个精心编排的交响乐。厨师(task)负责计算数字的总和,然后将结果交给服务员(future),由服务员将其交给顾客(main 线程)。

常见问题解答

1. Callable 和 Runnable 有什么区别?

Callable 返回一个结果,而 Runnable 则没有。

2. Future 和 synchronized 有什么关系?

Future 使用 synchronized 关键字来确保线程安全和结果的正确性。

3. Executor 有哪些不同类型?

有单线程、固定线程池和缓存线程池等类型的 Executor。

4. 如何处理异常?

Future 会传播由任务引发的异常。

5. 如何取消任务?

Future 提供了一个 cancel() 方法,但在我们自己的实现中,它已被禁用。