实例带你获取多线程Thread的返回值之 (贰) - Callable配合线程池返回数据

前言

阅读本篇文章,你需要先理解以下知识:

  • 第一章:Callable的使用(点我跳转
  • 多线程Thread的基本使用 (点我跳转
  • 线程池基本知识 (点我跳转
  • extends和implements
  • 重写Override
  • try catch错误处理
  • Java基础知识

回顾

在上一章(点我跳转)我们了解了Callable的基本使用,本次我们将把Callable运用到线程池(点我跳转)中。

拷贝

用你的IDE新建一个项目或类,并将类命名为TestThreadPool,然后将下面的代码替换到类中:

 1import java.util.ArrayList;
 2import java.util.List;
 3import java.util.concurrent.*;
 4
 5public class TestThreadPool {
 6    ExecutorService executorService = Executors.newFixedThreadPool(2);
 7    public static void main(String[] args) {
 8        //实例化类
 9        TestThreadPool testThreadPool = new TestThreadPool();
10        //调用动态方法
11        testThreadPool.threadPool();
12    }
13
14    public void threadPool() {
15        Thread1 thread1 = new Thread1();
16        Thread2 thread2 = new Thread2();
17        //将Future包装进List,实现添加结果
18        List<Future> resultList = new ArrayList<Future>();
19        for (int i = 0; i < 3; i++) {
20            System.out.println("线程池已提交:" + i);
21            Future res1 = executorService.submit(thread1);
22            Future res2 = executorService.submit(thread2);
23            //将获取的结果添加进List
24            resultList.add(res1);
25            resultList.add(res2);
26        }
27        System.out.println("正在关闭线程池...");
28        executorService.shutdown();
29        System.out.println("线程池已关闭.");
30        //executorService.shutdownNow();
31        //线程池运行结束,打印结果
32        for (int i = 0; i < resultList.size(); i++) {
33            Future future = resultList.get(i);
34            try {
35                System.out.println(future.get());
36            } catch (InterruptedException | ExecutionException e) {}
37        }
38    }
39}
40
41/**
42 * 线程1
43 */
44class Thread1 implements Callable {
45    @Override
46    public Object call() throws Exception {
47        try {
48            Thread.sleep(500);
49        } catch (Exception e) {}
50        return "本条数据来自线程1";
51    }
52}
53
54/**
55 * 线程2
56 */
57class Thread2 implements Callable {
58    @Override
59    public Object call() throws Exception {
60        try {
61            Thread.sleep(500);
62        } catch (Exception e) {}
63        return "本条数据来自线程2";
64    }
65}

对比

和线程池第二章的文章(点我跳转)中的实例代码对比一下,你会发现它们大概是相同的,此时再回顾一下Callable中的实例代码(点我跳转),你会发现这篇是这两篇的结合。

区别

定义的两个线程类:

 1/**
 2 * 线程1
 3 */
 4class Thread1 implements Callable {
 5    @Override
 6    public Object call() throws Exception {
 7        try {
 8            Thread.sleep(500);
 9        } catch (Exception e) {}
10        return "本条数据来自线程1";
11    }
12}
13
14/**
15 * 线程2
16 */
17class Thread2 implements Callable {
18    @Override
19    public Object call() throws Exception {
20        try {
21            Thread.sleep(500);
22        } catch (Exception e) {}
23        return "本条数据来自线程2";
24    }
25}

你会发现它不再使用Runnable了,而是使用了Callable以支持返回数据。并且重写的方法不再是run(),而是call()。我们使用return返回了String类型的字符串。

调用方法

 1public void threadPool() {
 2        Thread1 thread1 = new Thread1();
 3        Thread2 thread2 = new Thread2();
 4        //将Future包装进List,实现添加结果
 5        List<Future> resultList = new ArrayList<Future>();
 6        for (int i = 0; i < 3; i++) {
 7            System.out.println("线程池已提交:" + i);
 8            Future res1 = executorService.submit(thread1);
 9            Future res2 = executorService.submit(thread2);
10            //将获取的结果添加进List
11            resultList.add(res1);
12            resultList.add(res2);
13        }
14        System.out.println("正在关闭线程池...");
15        executorService.shutdown();
16        System.out.println("线程池已关闭.");
17        //executorService.shutdownNow();
18        //线程池运行结束,打印结果
19        for (int i = 0; i < resultList.size(); i++) {
20            Future future = resultList.get(i);
21            try {
22                System.out.println(future.get());
23            } catch (InterruptedException | ExecutionException e) {}
24        }
25    }

该方法仍是使用了同样的线程池,但执行方法使用了submit()而不是execute()。因为execute()方法只支持Runnable,请注意。

我们将Future套入了一个List中,以便异步循环写入每个线程执行后返回的结果。

请仔细阅读调试,这并不难理解。

运行!

现在,运行你的代码,你会看到以下结果:

 1线程池已提交:0
 2线程池已提交:1
 3线程池已提交:2
 4正在关闭线程池...
 5线程池已关闭.
 6本条数据来自线程1
 7本条数据来自线程2
 8本条数据来自线程1
 9本条数据来自线程2
10本条数据来自线程1
11本条数据来自线程2

后语

Java线程与线程池的知识点实际上是很多的。使用多线程是为了拥有更强的性能和更灵活的调用能力,同时也是每个合格的程序员必会的知识点。

如转载请在文章尾部添加

原作者来自 adlered 个人技术博客:https://www.stackoverflow.wiki/

    评论
    0 评论
avatar

取消