如何使用Java Executor框架进行多线程

Ťhis post was originally published in adityasridhar.com

In my Previous Blog I covered the basics of Multithreading in Java. Click here to read that blog.

先前的博客介绍了如何通过扩展Thread类并实现Runnable接口来创建线程。

本文将涵盖2个主题。

  • 通过实现Callable接口创建线程在Java中使用Executor框架

Implementing the Callable Interface

为了创建可以在Thread中运行的代码,我们创建一个类,然后实现可召回接口。 由这段代码完成的任务需要放在呼叫()功能。 在下面的代码中,您可以看到可召回Task是一个实现可召回接口,以及将0到4的数字求和的任务正在函数中完成。

import java.util.concurrent.Callable;
class CallableTask implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {

        int sum = 0;
        for (int i = 0; i < 5; i++) {
            sum += i;
        }
        return sum;
    }

}

在上面的代码中,您会注意到可召回参数为整数. This shows that the return type of this 可召回 will be 整数. Also it can be seen that the call function returns 整数类型。

Creating the Threads and running them

下面的代码显示了如何创建线程,然后运行它们。

import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableInterfaceDemo {

    public static void main(String[] args) {
        FutureTask<Integer>[] futureList = new FutureTask[5];

        for (int i = 0; i <= 4; i++) {
            Callable<Integer> callable = new CallableTask();
            futureList[i] = new FutureTask<Integer>(callable);
            Thread t = new Thread(futureList[i]);
            t.start();

        }

        for (int i = 0; i <= 4; i++) {
            FutureTask<Integer> result = futureList[i];
            try {
                System.out.println("Future Task" + i + ":" + result.get());
            } catch (InterruptedException e) {

                e.printStackTrace();
            } catch (ExecutionException e) {

                e.printStackTrace();
            }
        }

    }

}

为了创建线程,首先我们需要创建一个实例可召回Task实施可召回界面如图

Callable<Integer> callable = new CallableTask();

然后,我们需要创建一个实例未来任务类并传递实例可召回任务作为参数,如下所示

futureList[i] = new FutureTask<Integer>(callable);

然后创建一个线程,我们创建一个实例线类并传递的实例未来任务类作为参数,如

Thread t = new Thread(futureList[i]);

最后,线程以开始()功能。

Getting the result from the Thread

如果是Callables,线程实际上可以返回值。 为了获得此值,我们可以调用得到()在实例上的功能未来任务。 在我们的代码中,线程的返回值是0到4之间的数字之和。

如下面的代码片段所示

FutureTask<Integer> result = futureList[i];
try {
    System.out.println("Future Task" + i + ":" + result.get());
} catch (InterruptedException e) {

    e.printStackTrace();
} catch (ExecutionException e) {

    e.printStackTrace();
}

另外线程可能会抛出一个例外也可以用试着抓块。

Complete Code

这是到目前为止讨论的完整代码

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

class CallableTask implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {

        int sum = 0;
        for (int i = 0; i < 5; i++) {
            sum += i;
        }
        return sum;
    }

}

public class CallableInterfaceDemo {

    public static void main(String[] args) {
        FutureTask<Integer>[] futureList = new FutureTask[5];

        for (int i = 0; i <= 4; i++) {
            Callable<Integer> callable = new CallableTask();
            futureList[i] = new FutureTask<Integer>(callable);
            Thread t = new Thread(futureList[i]);
            t.start();

        }

        for (int i = 0; i <= 4; i++) {
            FutureTask<Integer> result = futureList[i];
            try {
                System.out.println("Future Task" + i + ":" + result.get());
            } catch (InterruptedException e) {

                e.printStackTrace();
            } catch (ExecutionException e) {

                e.printStackTrace();
            }
        }

    }

}

The Executor Framework

每次快速创建线程都是资源密集型的。 一个好的替代方法是已经设置了一些线程,然后将我们的任务分配给这些线程。 这是Executors类和ExecutorService非常有用的地方。

如何使用Java Executor框架进行多线程_第1张图片

上图显示了具有4个线程的线程池。 每当我们希望运行任何任务时,都可以将其分配给这些线程。 任务完成后,线程将被释放以承担其他任务。

How to use the Executor Framework

这是使用Executor框架的代码。

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;

class Worker implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {

        int sum = 0;
        for (int i = 0; i < 5; i++) {
            sum += i;
        }
        return sum;
    }

}

public class ExecutorDemo {

    public static void main(String[] args) {
        ExecutorService executors = Executors.newFixedThreadPool(4);
        Future<Integer>[] futures = new Future[5];
        Callable<Integer> w = new Worker();
        try {
            for (int i = 0; i < 5; i++) {
                Future<Integer> future = executors.submit(w);
                futures[i] = future;

            }

            for (int i = 0; i < futures.length; i++) {
                try {
                    System.out.println("Result from Future " + i + ":" + futures[i].get());
                } catch (InterruptedException e) {

                    e.printStackTrace();
                } catch (ExecutionException e) {

                    e.printStackTrace();
                }
            }
        } finally {
            executors.shutdown();
        }

    }

}

首先,我们创建一个工人类实现Callable并完成我们需要的任务。

接下来,我们需要创建一个执行器服务。

的执行者类具有多种实现执行器服务。

让我们用执行者类创建大小为4的固定线程池。操作如下

ExecutorService executors = Executors.newFixedThreadPool(4);

接下来,我们需要将我们的任务提交给执行者服务。 这是使用以下代码行完成的

Future<Integer> future = executors.submit(w);

提交任务后,我们获得了一个实例未来 Object. The 未来 Object is what will store the result of the Task.

Getting the result of the Thread

为了获得每个任务的结果,我们可以调用得到()的方法未来实例。 如下面的代码片段所示。

try {
    System.out.println("Result from Future " + i + ":" + futures[i].get());
} catch (InterruptedException e) {

    e.printStackTrace();
} catch (ExecutionException e) {

    e.printStackTrace();
}

线程也可以抛出一个异常,可以使用试着抓。

Some possible Scenarios of the Fixed Thread Pool

  • 在此示例中,我们创建了大小为4的固定线程池如果我们总共向此ExecutorService提交3个任务,则所有3个任务都将分配给线程池,并且它们将开始执行。如果我们向此ExecutorService提交4个任务,那么所有这4个任务都会再次分配给线程池,并且它们将开始执行。现在,如果我们向该线程池提交5个任务。 只有4个任务将分配给线程池。 这是因为线程池的大小为4。仅当释放池中的线程之一时,才会分配第五个任务。

Shutting down the ExecutorService

当不再需要线程时,需要关闭ExecutorService。 这将确保JVM不会消耗其他资源。

可以使用以下命令关闭ExecutorService

executors.shutdown();

可以看出,这种关机位于最后块。 这是为了确保即使在发生任何异常的情况下,关闭操作始终在代码末尾执行。

如果关闭操作不正确,则如果发生任何异常,则ExecutorService仍将运行,并且将消耗其他JVM资源。

Code

All the code discussed in this article can be found in this git repo

Congrats

现在您知道以下概念

  • 使用可调用接口使用Java Executor框架进行多线程处理。

在以后的文章中,我将介绍有关多线程的更多主题。

Feel free to connect with me in LinkedIn or follow me in twitter.

If you liked this post, you can checkout my website https://adityasridhar.com for other similar posts

from: https://dev.to//adityasridhar/how-to-use-java-executor-framework-for-multithreading-30oc

你可能感兴趣的:(如何使用Java Executor框架进行多线程)