Java中的Callable以及Future

Java多线程编程

Callable

Runnable封装了一个异步运行的任务,可以把它想象成为一个没有参数和返回值的异步方法。Callable和Runnable类似,但是有返回值,Callable接口是一个参数化的类型,只有一个方法call

public interface Callable
{
    V call() throws Exception
}

Future

Future可以保存异步计算的结果,可以启动一个计算,将Future对象交给某个线程,Future对象的所有者在结果计算好之后就可以获得它
Future接口具有下面的方法:

public interface Future
{
    V get() throws...;
    V get(long timeout, TimeUnit unit) throws...; 
    void cancel(boolean mayInterrupt);
    boolean isCancelled();
    boolean isDone();
}

FutureTask包装器

可以将Callable转换成Future和Runnable,它实现了二者的接口

Callable myComputation = ...;
FutureTask task = new FutureTask(myComputation);
Thread thread = new Thread(task);
thread.start();
...
Integer result = task.get(); // It `s future

调用get()方法会发生阻塞,直到结果可以获得为止。

相关事例

在Java多线程处理任务过程中,由于每一个线程处理完自身任务之后,需要将数据传出来,然后再经过整合,完成这个业务功能。
鉴于线程自身运行完毕阶段无法返回数据,可以通过Future对象交给线程,之后通过Future对象获取到计算结果
通过FutureTask包装器将Callable转换成Future和Runnable;
比如

package future;
import java.util.concurrent.*;

public class FutureTaskCount {
    // 定义4个计算线程
    Callable calculate1 = new Callable() {
        private int count = 0;
        @Override
        public Integer call() throws Exception {
            for (int i = 0; i < 4; i++) {
                count++;
                System.out.println("此时线程1正在运行 当前count: " + count);
                Thread.sleep(1000);
            }
            return count;
        }
    };

    Callable calculate2 = new Callable() {
        private int count = 0;
        @Override
        public Integer call() throws Exception {
            for (int i = 0; i < 4; i++) {
                count++;
                System.out.println("此时线程2正在运行 当前count: " + count);
                Thread.sleep(1000);
            }
            return count;
        }
    };

    Callable calculate3 = new Callable() {
        private int count = 0;
        @Override
        public Integer call() throws Exception {
            for (int i = 0; i < 4; i++) {
                count++;
                System.out.println("此时线程3正在运行 当前count: " + count);
                Thread.sleep(1000);
            }
            return count;
        }
    };

    Callable calculate4 = new Callable() {
        private int count = 0;
        @Override
        public Integer call() throws Exception {
            for (int i = 0; i < 4; i++) {
                count++;
                System.out.println("此时线程4正在运行 当前count: " + count);
                Thread.sleep(1000);
            }
            return count;
        }
    };

    public static void main(String[] args) {
        FutureTaskCount futureTaskCount = new FutureTaskCount();
        // 获取线程池
        ExecutorService executorService = Executors.newCachedThreadPool();
        FutureTask calculate1 = new FutureTask(futureTaskCount.calculate1);
        FutureTask calculate2 = new FutureTask(futureTaskCount.calculate2);
        FutureTask calculate3 = new FutureTask(futureTaskCount.calculate3);
        FutureTask calculate4 = new FutureTask(futureTaskCount.calculate4);

        executorService.submit(calculate1);
        executorService.submit(calculate2);
        executorService.submit(calculate3);
        executorService.submit(calculate4);
        try {
            System.out.println(calculate1.get());
            System.out.println(calculate2.get());
            System.out.println(calculate3.get());
            System.out.println(calculate4.get());
            System.out.println("所有线程计算均执行完毕");
        } catch (InterruptedException exception) {
            exception.printStackTrace();
        } catch (ExecutionException exception) {
            exception.printStackTrace();
        }

    }
}

当所有线程的计算均完毕时候,才会打印出 "所有线程计算均执行完毕",也就是调用get()方法会发生阻塞,直到结果可以获得为止。executorService.submit的调用,相当于启动线程操作了,以上代码中需要将call()方法overwrite。此时,每个线程可以独立运行任务。最后直接调用get()获取每个线程计算结果

执行器(Executor)

执行器有许多方法来构建线程池,比如newCachedThread方法构建了一个线程池,对于每个任务,如果有空闲线程可用,立即让它执行任务,如果没有可用的线程,则创建一个新线程,那么把得不到服务的任务放置到队列中。当其他任务完成以后再运行它们。

你可能感兴趣的:(Java中的Callable以及Future)