通过 Callable 和 Future(或 FutureTask)创建线程

在Java中,可以使用Callable和Future创建线程。Callable接口类似于Runnable接口,但是它可以返回一个结果并且可以抛出异常。Future则是用于表示异步计算的结果,可以等待计算完成并且获取结果。

Callable 和 Future 的优点

使用Callable和Future创建线程相较于直接使用Runnable接口或Thread类有一些优点和好处:

  1. 能够返回结果:Callable接口可以返回计算的结果,这在某些场景下非常有用。例如,如果你需要执行一个耗时的计算任务,并且需要获取计算的结果进行后续处理,那么Callable就可以很方便地实现这个需求。
  2. 能够抛出异常 :Callable接口的call()方法可以声明抛出异常,这使得在执行过程中出现异常时能够更好地处理错误情况,而不是直接使线程崩溃。
  3. 更灵活的线程池管理:ExecutorService接口提供了灵活的线程池管理,可以方便地控制并发线程数量、提交任务、获取任务执行结果等。使用Callable和Future结合ExecutorService可以更加方便地管理并发任务。
  4. 阻塞等待任务完成 :Future对象的get()方法可以阻塞当前线程,直到任务执行完成并返回结果。这在需要等待任务执行完成后再继续执行后续操作时非常有用。
  5. 支持取消任务 :Future对象提供了cancel()方法,可以取消任务的执行。这在某些情况下可以帮助避免资源浪费或处理超时任务。

总的来说,使用Callable和Future创建线程能够提供更灵活、更可控的并发执行方式,使得多线程编程更加方便、高效、安全。

Callable 和 Future 的使用步骤

  1. 创建Callable任务 :首先,你需要创建一个实现了Callable接口的任务类,该接口要求实现call()方法,该方法表示需要执行的具体任务,并且可以返回一个结果。
  2. 创建ExecutorService:接下来,你需要创建一个ExecutorService对象,它用于管理线程池和执行任务。
  3. 提交任务 :使用ExecutorService的submit()方法提交Callable任务。这个方法会返回一个Future对象,用于表示任务的执行情况和结果。
  4. 获取Future对象 :通过调用submit()方法后返回的Future对象,你可以对任务进行管理,例如等待任务执行完成或者取消任务。
  5. 获取结果 :如果你需要获取任务执行的结果,可以调用Future对象的get()方法。这个方法会阻塞当前线程,直到任务执行完成并返回结果。
  6. 关闭ExecutorService :当所有任务执行完成后,记得调用ExecutorService的shutdown()方法关闭线程池,释放资源。

Callable 和 Future 的代码样例

下面是一个简单的示例,演示了如何使用Callable和Future创建线程:

java 复制代码
import java.util.concurrent.*;

public class CallableAndFutureDemo {

    public static void main(String[] args) {
        // 创建一个线程
        ExecutorService executor = Executors.newSingleThreadExecutor();

        // 创建一个 Callable 任务
        Callable<Integer> callable = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                // 模拟一个耗时操作
                Thread.sleep(2000);
                return 123;
            }
        };

        // 提交任务并获取 Future 对象
        Future<Integer> future = executor.submit(callable);

        // 等待计算完成并获取结果
        try {
            // 这一步会阻塞,直到任务完成
            Integer result = future.get();
            System.out.println("result: " + result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }

        // 关闭线程池
        executor.shutdown();
    }

}

这个示例中,我们创建了一个Callable任务,并通过ExecutorService的submit()方法提交该任务。然后,我们通过Future对象的get()方法等待任务执行完成并获取结果。最后,我们调用ExecutorService的shutdown()方法关闭线程池。

FutureTask 的优点

当使用Callable和Future时,经常会使用到FutureTask类。FutureTask是Future接口的实现类,同时也实现了Runnable接口,因此它可以被提交到ExecutorService中执行,并且可以作为Future对象来获取任务的执行结果。

以下是FutureTask的优点和使用方法:

  1. 方便的结合Callable和Runnable:FutureTask既可以包装Callable任务,也可以直接包装Runnable任务,这使得使用FutureTask非常灵活,既可以获取任务执行结果,又可以在ExecutorService中执行。
  2. 简化线程管理:FutureTask提供了一种方便的方式来管理异步任务。通过将任务包装在FutureTask中,可以更容易地提交、取消、等待和获取任务的执行结果。
  3. 异常处理 :FutureTask能够处理Callable任务中抛出的异常。如果任务执行过程中出现异常,调用FutureTask的get()方法会抛出ExecutionException,并将原始异常作为其cause。
  4. 支持取消任务 :FutureTask提供了cancel()方法来取消任务的执行。可以选择传入一个布尔值参数来指定是否中断正在执行的任务。
  5. 支持多线程操作:FutureTask是线程安全的,可以在多个线程中安全地使用。

FutureTask 的示例代码1

使用FutureTask的示例代码如下:

java 复制代码
import java.util.concurrent.*;

public class CallableAndFutureTaskDemo {

    public static void main(String[] args) {

        // 创建一个 Callable 任务
        Callable<Integer> callable = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                // 模拟一个耗时操作
                Thread.sleep(2000);
                return 123;
            }
        };

        // 提交任务并获取 Future 对象
        FutureTask<Integer> future = new FutureTask<>(callable);

        // 创建一个线程池
        ExecutorService executor = Executors.newSingleThreadExecutor();

        // 提交 FutureTask 任务
        executor.submit(callable);

        // 获取任务执行结果
        try {
            // 这一步会阻塞,直到任务完成
            Integer result = future.get();
            System.out.println("result: " + result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }

        // 关闭线程池
        executor.shutdown();
    }

}

在这个示例中,我们创建了一个Callable任务,并使用FutureTask包装了它。然后,我们将FutureTask提交到ExecutorService中执行,并通过调用get()方法获取任务的执行结果。最后,我们关闭了ExecutorService。

FutureTask 的示例代码2

使用 Callable, FutureTask 和 Thread,而不是线程池来创建线程,代码示例如下:

java 复制代码
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class CallableAndFutureTaskDemo1 {

    public static void main(String[] args) {
        
        // 创建一个Callable任务
        Callable<Integer> callable = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                // 模拟一个耗时操作
                Thread.sleep(2000);
                return 123;
            }
        };

        // 创建FutureTask对象
        FutureTask<Integer> futureTask = new FutureTask<>(callable);

        // 创建一个线程,并将FutureTask作为其构造函数参数
        Thread thread = new Thread(futureTask);

        // 启动线程
        thread.start();

        // 获取任务执行结果
        try {
            Integer result = futureTask.get(); // 这一步会阻塞直到任务完成
            System.out.println("Result: " + result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

在这个示例中,我们创建了一个Callable任务,并使用FutureTask包装了它。然后,我们创建了一个Thread对象,将FutureTask作为其构造函数参数传入,这样Thread就知道要执行的任务。接着,我们启动了线程并等待任务执行完成,最后获取任务的执行结果。

相关推荐
程序员南飞40 分钟前
ps aux | grep smart_webrtc这条指令代表什么意思
java·linux·ubuntu·webrtc
弥琉撒到我44 分钟前
微服务swagger解析部署使用全流程
java·微服务·架构·swagger
一颗花生米。2 小时前
深入理解JavaScript 的原型继承
java·开发语言·javascript·原型模式
问道飞鱼2 小时前
Java基础-单例模式的实现
java·开发语言·单例模式
ok!ko5 小时前
设计模式之原型模式(通俗易懂--代码辅助理解【Java版】)
java·设计模式·原型模式
2401_857622666 小时前
SpringBoot框架下校园资料库的构建与优化
spring boot·后端·php
2402_857589366 小时前
“衣依”服装销售平台:Spring Boot框架的设计与实现
java·spring boot·后端
吾爱星辰6 小时前
Kotlin 处理字符串和正则表达式(二十一)
java·开发语言·jvm·正则表达式·kotlin
哎呦没7 小时前
大学生就业招聘:Spring Boot系统的架构分析
java·spring boot·后端
_.Switch7 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j