多线程学习总结(四)——实现多线程的方法之Callable和Futura

    声明:文章内容全都是自己的学习总结,如有不对的地方请大家帮忙指出。有需要沟通交流的可加我QQ群:425120333
    前面提到的实现Runnable接口和继承Thread类的方式都是没有返回值的,而这次要是的通过实现Callable接口的方式实现是能够有返回值的,
集体的返回值类型可根据需要自己指定,这个返回值可以是一个对象,也可以是一个容器类(根据需求),既然有返回值,那就必须要获取到,
而Futura就是为了获取Callable在多线程情况下的返回值。
    看一个简单的例子:
public class TestCallable implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        return 1;
    }

    public static void main(String[] args) {
        FutureTask<Integer> futureTask = new FutureTask<Integer>(new TestCallable());
        new Thread(futureTask).start();
        try {
            //get()方法是一个阻塞方法,如果线程未执行好,就会一直阻塞
            Integer result = futureTask.get();
            System.out.println(result);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

这里通过FutureTask来获取TestCallable执行结果的返回值, FutureTask实现了两个接口,Runnable和Future,所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。
关于Future模式这里有个介绍可以参考下 http://openhome.cc/Gossip/DesignPattern/FuturePattern.htm

接下来通过线程池来获取Callable的结果,相比较前一中,会简单一些

public class TestCallable implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        return 1;
    }

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService service = Executors.newCachedThreadPool();
        Future<Integer> future = service.submit(new TestCallable());
        try {
            //get()方法是一个阻塞方法,如果线程未执行好,就会一直阻塞
            Integer result = future.get();
            System.out.println(result);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

看到这里,有人可能会提出疑惑,我的线程池如果是提交多个任务的,那怎么保证每个的结果能对应下呢?
这里有两种解决方案,第一种是按照提交到线程池的顺序挨个获取返回值,代码示例:

public class TestCallable implements Callable<Integer> {

    private Integer id;

    public TestCallable(int id) {
        this.id = id;
    }

    @Override
    public Integer call() throws Exception {
        return id;
    }

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        //构建一个存放Future对象的容器,循环遍历出其中的每一个
        List<Future<Integer>> futureList = new ArrayList<Future<Integer>>();
        ExecutorService service = Executors.newCachedThreadPool();
        for (int i = 0; i < 5; i++) {
            Future<Integer> future = service.submit(new TestCallable(i));
            futureList.add(future);
        }
        for (Future<Integer> future : futureList) {
            System.out.println(future.get());
        }
    }
}

控制台显示:
0
1
2
3
4
这样虽然能够按照顺序获取到相应的结果,但如果其中某个阻塞住的话,后面的就无法获取结果值了(除非知道是那个阻塞住,从而跳过);
第二种方法是通过使用CompletionService,示例如下

public class TestCallable implements Callable<Integer> {

    private Integer id;

    public TestCallable(int id) {
        this.id = id;
    }

    @Override
    public Integer call() throws Exception {
        if (id == 3) {
            //加个睡眠时间使得结果更加明显
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return id;
    }

    public static void main(String[] args) throws Exception {

        ExecutorService service = Executors.newCachedThreadPool();
        CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(
                service);
        for (int i = 0; i < 5; i++) {
            completionService.submit(new TestCallable(i));
        }
        for (int i = 0; i < 5; i++) {
            System.out.println(completionService.take().get());
        }
    }
}

控制台显示:
0
2
1
4
3
提交到CompletionService中的Future是按照完成的顺序排列的,和提交的先后没有影响,因为id=3时加了一个睡眠,所以3总是最后一个输出,前面几个输出顺序不一定。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值