什么是Java Executor 框架?
随着当今处理器中可用内核数量的增加,再加上实现更高吞吐量的需求不断增加,多线程 API 变得越来越流行。 Java提供了自己的多线程框架,称为Java Executor Framework。
Java executor 框架(Java.util.concurrent.Executor),与JDK 5 一起发布,用于运行Runnable 对象,而无需每次都创建新线程,并且主要重用已经创建的线程。我们都知道在Java创建线程有两种方式。如果您想了解更多关于它们的比较,请阅读如何在Java创建线程。
Java.util.concurrent.Executors 提供了用于创建工作线程的 ThreadPools 的工厂方法。线程池通过保持线程处于活动状态并重用线程来克服这个问题。池中的线程可以处理的任何流入的多余任务都保存在队列中。一旦任何线程获得空闲,它们就会从该队列中选择下一个任务。对于 JDK 提供的开箱即用的执行器,此任务队列本质上是无界的。
下面列出了一些类型的Java Executor:
- 单线程执行器
- 固定线程池(n)
- 缓存线程池
- 预定执行器
让我们讨论这些流行的Java executors 的一些细节,在实现它们之前,它们究竟做了什么以获得更好的想法。
Executor 1: SingleThreadExecutor
调用Executors类的静态newSingleThreadExecutor()方法可以获得单个线程池。它用于顺序执行任务。
句法:
ExecutorService executor = Executors.newSingleThreadExecutor();
执行器 2: FixedThreadPool(n)
顾名思义,它是一个线程数量固定的线程池。提交给执行器的任务由 n 个线程执行,如果有更多任务,它们将存储在 LinkedBlockingQueue 中。它使用阻塞队列。
句法:
ExecutorService fixedPool = Executors.newFixedThreadPool(2);
Executor 3: CachedThreadPool
创建一个线程池,根据需要创建新线程,但在可用时将重用先前构造的线程。如果可用,调用 execute 将重用先前构造的线程。如果没有可用的现有线程,则会创建一个新线程并将其添加到池中。它使用 SynchronousQueue 队列。
ExecutorService executorService = Executors.newCachedThreadPool();
Executor 4: ScheduledExecutor
调度执行器基于接口 ScheduledExecutorService,它扩展了 ExecutorService 接口。当我们有一个需要定期运行的任务或者我们希望延迟某个任务时,就会使用这个执行器。
ScheduledExecutorService scheduledExecService = Executors.newScheduledThreadPool(1);
- 可以使用以下两种方法之一来安排任务:
- scheduleAtFixedRate :以固定的时间间隔执行任务,无论上一个任务何时结束。
- scheduleWithFixedDelay :只有在当前任务完成后才会开始延迟倒计时。`
句法:
scheduledExecService.scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
scheduledExecService.scheduleWithFixedDelay(Runnable command, long initialDelay, long period, TimeUnit unit)
Future Object
The result of the task submitted for execution to an executor can be accessed using the java.util.concurrent.The future object returned by the executor. Future can be thought of as a promise made to the caller by the executor. The future interface is mainly used to get the results of Callable results. whenever the task execution is completed, it is set in this Future object by the executor.
句法:
Future result = executorService.submit(callableTask);
实现:创建并执行一个简单的执行器,我们将在其中创建一个任务并在固定池中执行它
- Task 类实现 Callable 并被参数化为 String 类型。它也被声明为抛出异常。
- 现在为了在“Task”类中执行任务,我们必须实例化 Task 类并将其传递给执行程序以执行。
- 打印并显示 Future 对象返回的结果
例子
Java
// Java Program demonstrating Introduction to Java Executor
// Framework
// Importing concurrent classes from java.util package
import java.util.concurrent.*;
// Class 1
// Helper Class implementing runnable interface Callable
class Task implements Callable {
// Member variable of this class
private String message;
// Constructor of this class
public Task(String message)
{
// This keyword refers to current instance itself
this.message = message;
}
// Method of this Class
public String call() throws Exception
{
return "Hiiii " + message + "!";
}
}
// Class 2
// Main Class
// ExecutorExample
public class GFG {
// Main driver method
public static void main(String[] args)
{
// Creating an object of above class
// in the main() method
Task task = new Task("GeeksForGeeks");
// Creating object of ExecutorService class and
// Future object Class
ExecutorService executorService
= Executors.newFixedThreadPool(4);
Future result
= executorService.submit(task);
// Try block to check for exceptions
try {
System.out.println(result.get());
}
// Catch block to handle the exception
catch (InterruptedException
| ExecutionException e) {
// Display message only
System.out.println(
"Error occured while executing the submitted task");
// Print the line number where exception occured
e.printStackTrace();
}
// Cleaning resource and shutting down JVM by
// saving JVM state using shutdown() method
executorService.shutdown();
}
}
输出:
Hiiii GeeksForGeeks
Conclusion:
Multi-threading is getting increasingly mainstream as the processor clock-speed is difficult to increase. However, handling the lifecycle of each thread is very difficult due to the complexity involved.