【Java】Callable 接口

本文详细介绍了Java多线程中Callable接口与Future接口的作用与使用方式,对比了Runnable接口,并提供了具体的示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

多线程中最常用的是Runnable接口,定义了一次任务执行的内容。但是Runnable接口无法得到返回值,而且也无法让执行端捕获到异常。所以就有了Callable接口。

public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}
这是Callable接口的定义。

可以看到call方法可以抛出异常或者返回一个值。但是执行端该怎么处理呢?我们一旦起了一个线程,就需要得到返回值,但是这个返回值什么时候返回并不知道,因为是异步的,而且是得到返回值还是捕获了异常也不清楚,所以情况还是比较复杂的。这些都需要进行进一步的封装,也就是Future接口。个人认为,Future接口的存在是为了封装对任务执行情况的获取。主要有:

 boolean cancel(boolean mayInterruptIfRunning);

    boolean isCancelled();

    boolean isDone();

    
    V get() throws InterruptedException, ExecutionException;


    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
因为返回结果不确定何时返回,所以获取是一个阻塞式的操作,只有任务执行完了才返回,否则阻塞。Future接口正式干这个事情的。除了阻塞的get方法外,还有判断知否执行完的方法,相当于提供了一种非阻塞式的获取,我们可以在get前判断一下,如果执行完了再get。调用get时,因为可能爆出异常,所以要用try catch。

所以说Future和Callable是搭配在一起使用的。

使用的方法有两种

第一种,与线程池搭配。
那么在任务执行处就可以接收到一个Future,然后我们可以通过Future来获取结果。

public static void test1(){
		ExecutorService pool = Executors.newCachedThreadPool();
		Future<String> result = pool.submit(new Callable<String>() {
			@Override
			public String call() throws Exception {
				Thread.sleep(2000);
				return "ok";
			}
		});
		try {
			System.out.println(result.get());
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
	}
第二种,非线程池。那么也就是使用一个Thread来启动。但是Thread只能接受一个Runnable的接口,而且Runnable执行完start方法以后并不能返回任何值,所以此时应对这种情况,又封装了一个新的类TutureTask,该类同时继承了Future和Runnable接口,所有我们可以把它传给一个Thread,而且还可以通过它来获取返回值。其内部自然会有一个Callable的引用。本质上可以把FutureTask看成是一种扩展了的Runnable接口,内部维护了执行的情况,可以让我们得到返回值。

public static void test2(){
		FutureTask<String> task = new FutureTask<>(new Callable<String>() {

			@Override
			public String call() throws Exception {
				return "ok";
			}
		});
		Thread t = new Thread(task);
		t.start();
		try {
			System.out.println(task.get());
		} catch (InterruptedException | ExecutionException e) {
			e.printStackTrace();
		}
	}
这样就搞清楚了Callable,Runnable,Future和FutureTask接口的作用。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值