Executor introduction

A thread in Java is both a unit of work and an execution mechanism. Since JDK 5, the unit of work and the execution mechanism have been separated. The unit of work includes Runnable and Callable, and the execution mechanism is provided by the Executor framework in the java.util.concurrent package added in JDK 5.

The thread model of HotSpot VM maps java threads to threads of the local operating system. The start of a java thread means the creation of a thread of the local operating system, and the termination of a java thread means the recycling of the corresponding system thread.

 

The Executor framework mainly consists of three parts:

Tasks: including Runnable and Callable, where Runnable represents a task that can be executed asynchronously, and Callable represents a task that produces results

Task execution: including the core interface Executor of the Executor framework and its sub-interface ExecutorService. In the Executor framework, there are two key classes ThreadPoolExecutor and ScheduledThreadPoolExecutor that implement the ExecutorService interface.

The result of asynchronous calculation: including the interface Future and its implementation class FutureTask.

 

The following is an introduction to some key interfaces and classes in the Executor framework

 

Executor interface (java.util.concurrent.Executor)

It is the foundation and core of Executor and is defined as follows:

public interface Executor {
    void execute(Runnable command);
}

 

It contains a method execute, the parameter is a Runnable interface reference.

The Executor interface separates the submission and execution of tasks.

 

ThreadPoolExecutor类(java.util.concurrent.ThreadPoolExecutor)

It is the core implementation class of the thread pool, which is used to execute the submitted tasks.

It is usually created by the factory class Executors. Executors can create different ThreadPoolExecutors such as SingleThreadExecutor, FixedThreadPool and CachedThreadPool.

 

SingleThreadExecutor uses a single thread to execute tasks. The APIs provided by Executors are as follows:

public static ExecutorService newSingleThreadExecutor();
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory);

SingleThreadExecutor guarantees the order of task execution, and there is no multi-threaded activity.

 

 FixedThreadPool is a thread pool that uses a fixed number of threads. The API provided by Executors has the following two

1 public static ExecutorService newFixedThreadPool(int nThreads);
2 public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory);

FixedThreadPool满足了资源管理的需求,可以限制当前线程数量。适用于负载较重的服务器环境。

 

CachedThreadPool是无界线程池,Executors提供的API有如下两个

public static ExecutorService newCachedThreadPool();
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory);

CachedThreadPool适用于执行很多短期异步任务的小程序,适用于负载较轻的服务器。

 

ScheduledThreadPoolExecutor类(java.util.concurrent.ScheduledThreadPoolExecutor)

它是ThreadPoolExecutor的子类且实现了ScheduledExecutorService接口,它可以在给定的延迟时间后执行命令,或者定期执行命令,它比Timer更强大更灵活。

 Executors可以创建的ScheduledThreadPoolExecutor的类型有ScheduledThreadPoolExecutor和SingleThreadScheduledExecutor等

 

ScheduledThreadPoolExecutor具有固定线程个数,适用于需要多个后台线程执行周期任务,并且为了满足资源管理需求而限制后台线程数量的场景,Executors中提供的API有如下两个:

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize);
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory);

 

SingleThreadScheduledExecutor具有单个线程,Executors提供的创建API有如下两个:

public static ScheduledExecutorService newSingleThreadScheduledExecutor();
public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory);

它适用于单个后台线程执行周期任务,并且保证顺序一致执行的场景。

 

上述的ThreadPoolExecutor和ScheduledThreadPoolExecutor都可以用于执行Runnable与Callable接口的实现类

 

 

Future接口(Java.concurrent.Future)

Future代表着提交的任务的计算状态与结果,可以对其进行取消,查询是否取消,查询是否完成,查询结果等操作。

首先来看一下Future接口的定义:

复制代码
public interface Future<V> {

    boolean cancel(boolean mayInterruptIfRunning);

    boolean isCancelled();

    boolean isDone();

    V get() throws InterruptedException, ExecutionException;

    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;

}
复制代码

 

FutureTask类间接实现了Future接口,它用来表示异步计算的结果。当ThreadPoolExecutor或者ScheduledThreadPoolExecutor执行Runnable接口或者Callable接口的实现类时,它们会返回一个Future接口引用(实现类为FutureTask)。

 

 Runnable接口或者Callable接口的实现类在被上述两者执行的区别是,前者没有返回结果,而后者可以返回结果。Runnable可以通过Executors提供的API(Executors#callable)包装为Callable。

 

 

 

 

本文参考资料:《Java并发编程的艺术》以及其他网上文档 

 

-----------------------------------------------------------------------------------------------------------------

下面是一些简单的Demo程序

复制代码
 1 import java.util.concurrent.Executor;
 2 import java.util.concurrent.Executors;
 3 
 4 public class ExecutorTest {
 5     public static void main(String[] args) {
 6 
 7         Runnable hello = () -> {
 8             for (int i = 0; i < 100; i++) {
 9                 System.out.println(i + " hello");
10             }
11         };
12         Runnable bye = () -> {
13             for (int i = 0; i < 100; i++) {
14                 System.out.println(i + " bye");
15             }
16         };
17 
18         Executor executor = Executors.newCachedThreadPool();
19 
20         executor.execute(hello);
21         executor.execute(bye);
22 
23     }
24 }
复制代码

上面程序使用了两个Runnable任务hello和bye来打印相应语句,程序将会交错打印hello和bye。如果将executor改为SingleThreadExecutor,将会先打印100个"hello",再打印100个"bye"。

 

复制代码
 1 import java.util.ArrayList;
 2 import java.util.List;
 3 import java.util.Random;
 4 import java.util.concurrent.Callable;
 5 import java.util.concurrent.ExecutionException;
 6 import java.util.concurrent.ExecutorService;
 7 import java.util.concurrent.Executors;
 8 import java.util.concurrent.Future;
 9 
10 public class ExecutorTest {
11     public static void main(String[] args) {
12         Random random = new Random();
13         List<Integer> numbers = new ArrayList<>();
14         for (int i = 0; i < 100000; i++) {
15             numbers.add(random.nextInt(100000));
16         }
17         int result = calculate(numbers, 3);
18         System.out.println(result);
19     }
20 
21     public static int calculate(List<Integer> numbers,int digit) {
22         List<Callable<Integer>> tasks = new ArrayList<>();
23         for (Integer x : numbers) {
24             tasks.add(() -> {
25                 int count=0;
26                 int y=x;
27                 do {
28                     if (y % 10 == digit) {
29                         count++;
30                     }
31                     y /= 10;
32                 } while (y > 0);
33                 return count;
34             });
35         }
36         ExecutorService service = Executors.newFixedThreadPool(10);
37         int answer=0;
38         try {
39             List<Future<Integer>> results = service.invokeAll(tasks);
40             for (Future<Integer> result : results) {
41                 try {
42                     answer+=result.get();
43                 } catch (ExecutionException e) {
44                     e.printStackTrace();
45                 }
46             }
47         } catch (InterruptedException e) {
48             e.printStackTrace();
49         }
50         return answer;
51     }
52 }
复制代码

上面的程序随机生成了100000个随机数,然后统计这些数字中每个数字10进制中具有多少个数位3的数量和。使用具有10个线程的线程池进行计算,最终通过Future引用对象的结果来统计答案。

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326254081&siteId=291194637