理解java多线程中ExecutorService使用

  

接下来我会为你详细讲解 “理解Java多线程中ExecutorService使用”的完整攻略。

1. ExecutorService 是什么?

ExecutorService 接口是 Java 并发 API 提供的一个线程池管理器。它可以管理一个池子中的线程数量,也可以通过合理配置线程池中的参数,来提高系统的吞吐量和性能。

2. ExecutorService 线程池的种类

ExecutorService 已经有很多不同的实现类了,其中常用的有以下几种:

2.1. FixedThreadPool

FixedThreadPool(固定大小线程池)是指在初始化线程池的时候设置线程数目,线程数目不会变化。

2.2. CachedThreadPool

CachedThreadPool(缓存线程池)是指在运行的过程中,根据需要创建新的线程,当线程超过一定时间没有被使用,就自动销毁。

2.3. SingleThreadPool

SingleThreadPool(单线程池)是指只有一个核心线程,也就是线程池的最大容量为 1。通常用于这种场景:需要处理逐一处理任务,而不是并发的处理任务。

2.4. ScheduledThreadPool

ScheduledThreadPool(定时任务线程池)是指在固定时间间隔内执行定时任务线程池。

3. ExecutorService 的使用方法

首先,在使用 Runnable 或者 Callable 作为 Thread 的构造函数的时候,我们可以将这些的目标作为 向Executor提交的任务(Task)

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("MyRunnable");
    }
}

public class Main{
    public static void main(String args[]){
        ExecutorService threadPool = Executors.newFixedThreadPool(5);
        threadPool.execute(new MyRunnable()); // 向线程池提交任务
}

4. ExecutorService 中 submit 方法和 execute 方法的区别

submit 方法和 execute 方法都可以向线程池提交任务,但是他们还是存在一定的区别:

  • submit 方法会【返回一个 Future】,这个 Future 可以操作刚提交的 Task 的结果
public class MyCallable implements Callable {
    @Override
    public Object call() throws Exception {
        System.out.println("MyCallable");
        return "result";
    }
}

public class Main {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor(); 
        Future<String> future = executorService.submit(new MyCallable());
        try {
            String result = future.get(); // 拿到 callable 的结果
            System.out.println(result); // 打印结果
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}
  • execute 方法则不会返回结果。
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("MyRunnable");
    }
}

public class Main {
    public static void main(String args[]){
         ExecutorService threadPool = Executors.newFixedThreadPool(5);
         threadPool.execute(new MyRunnable());
         threadPool.shutdown(); //关闭线程池
    }
}

5. ExecutorService 的关闭

当我们使用完 ExecutorService 线程池之后,需要进行关闭。

这时,我们可以使用 shutdown 方法进行关闭,如下所示。

public class Main {
    public static void main(String args[]){
         ExecutorService threadPool = Executors.newFixedThreadPool(5);
         threadPool.execute(new MyRunnable());
         threadPool.shutdown(); //关闭线程池
    }
}

6. 示例说明

6.1. 示例1:Runnable 使用 ExecutorService

下面的代码演示了 Runnable 如何使用 ExecutorService。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {
    public static void main(String args[]){
        ExecutorService threadPool = Executors.newFixedThreadPool(5);
        for (int i = 0;i<5;i++){
            MyRunnable myRunnable = new MyRunnable();
            threadPool.execute(myRunnable);
        }
        threadPool.shutdown();
    }
}

class MyRunnable implements Runnable {
    public void run() {
        System.out.println(Thread.currentThread().getName() + " 正在执行 task.");
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

代码说明:

  • 这里我们首先创建一个 ExecutorService 对象 threadPool,它是一个 FixedThreadPool 类型的线程池,最大线程数为 5。
  • 然后我们创建 5 个需要执行的 Task(Runable),然后分别通过 ExecutorService 来 管理它们的执行。
  • 最后通过 threadPool.shutdown() 方法等待所有的 Task 都已经执行完成,然后关闭这个ExecutorService。

输出结果如下:

pool-1-thread-1 正在执行 task.
pool-1-thread-2 正在执行 task.
pool-1-thread-3 正在执行 task.
pool-1-thread-4 正在执行 task.
pool-1-thread-5 正在执行 task.

6.2. 示例2:Callable 使用 ExecutorService

下面的代码则演示了 Callable 如何使用 ExecutorService:

import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Main {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        ArrayList<Future<String>> futureList = new ArrayList<>();

        for(int i=0;i<10;i++){
            MyTask myTask = new MyTask(i);
            futureList.add(executorService.submit(myTask));
        }
        executorService.shutdown();

        for(Future<String> future:futureList){
            System.out.println(future.get());
        }
    }
}

class MyTask implements Callable<String> {
    int i;
    public MyTask(int i){
        this.i = i;
    }

    @Override
    public String call() throws Exception {
        System.out.println("正在执行一个Task: 执行第 "+i+" 个 task.");
        Thread.sleep(5000);
        return "结果:" + i;
    }
}

代码说明:

  • 这里我们首先创建一个 ExecutorService 对象,它是一个 FixedThreadPool 类型的线程池,最大线程数为 2。
  • 然后我们创建 MyTask 类,作为要执行的 10 个 Task,每个 Task 执行 5 秒。
  • 我们把所有的 Task 放入到一个 ArrayList 中,然后使用 executorService 来管理它们。
  • 使用 futureList 来存储所有 Task 的结果,最后将结果输出。

输出结果如下:

正在执行一个Task: 执行第 4 个 task.
正在执行一个Task: 执行第 5 个 task.
正在执行一个Task: 执行第 0 个 task.
正在执行一个Task: 执行第 1 个 task.
正在执行一个Task: 执行第 2 个 task.
正在执行一个Task: 执行第 3 个 task.
正在执行一个Task: 执行第 6 个 task.
正在执行一个Task: 执行第 7 个 task.
正在执行一个Task: 执行第 8 个 task.
正在执行一个Task: 执行第 9 个 task.
结果:0
结果:1
结果:2
结果:3
结果:4
结果:5
结果:6
结果:7
结果:8
结果:9
相关文章