Java Executors线程池创建工具类介绍

x33g5p2x  于2021-08-22 转载在 Java  
字(10.3k)|赞(0)|评价(0)|浏览(330)

在这篇文章中,我们将结合实例讨论重要的并发效用执行器类。我们将在例子中使用Java 8 Lambda表达式。

Executors类为本包中定义的Executor、ExecutorService、ScheduledExecutorService、ThreadFactory和Callable类提供工厂和实用方法。
该类支持以下种类的方法。

  • 创建并返回具有常用配置设置的ExecutorService的方法。
  • 用常用的配置设置创建并返回一个ScheduledExecutorService的方法。
  • 创建并返回一个 "包装好的 "ExecutorService的方法,该方法通过使特定的实现方法无法访问来禁止重新配置。
  • 创建并返回一个ThreadFactory的方法,该方法将新创建的线程设置为一个已知的状态。
  • 创建并返回一个Callable的方法,该方法从其他类似闭包的形式出来,因此它们可以被用于需要Callable的执行方法中。
    Executors Utility类提供了一个列表工厂和实用方法,在下面的类图中显示。

在这篇文章中,我们将结合实例讨论Executors类的五个重要的实用方法。

  1. Executors.newFixedThreadPool(int nThreads) 方法
  2. Executors.newSingleThreadExecutor() 方法
  3. Executors.newCachedThreadPool() 方法
  4. Executors.newScheduledThreadPool方法
  5. Executors.newSingleThreadScheduledExecutor() 方法

1. Executors.newFixedThreadPool(int nThreads)方法

创建一个线程池,重用固定数量的线程在一个共享的无界队列中运行。在任何时候,最多只有nThreads 个线程在处理任务。如果在所有线程都处于活动状态时提交了额外的任务,它们将在队列中等待,直到有线程可用。如果任何线程在关机前的执行过程中因故障而终止,如果需要执行后续任务,将有一个新的线程取代它的位置。池中的线程将存在,直到它被明确关闭。

**参数。 **nThreads 池中线程的数量
返回:新创建的线程池

抛出。 IllegalArgumentException - 如果nThreads <= 0
语法:

ExecutorService executorService = Executors.newFixedThreadPool(noOfThreads);

Java newFixedThreadPool例子

让我们创建一个非常简单的例子。

第一步:创建一个名为 "Task.java "的Runnable 任务。

class Task implements Runnable {
    @Override
    public void run() { 
         for (int i = 0; i < 5; i++) {
              System.out.println("[" + Thread.currentThread().getName() + "] " + "Message " + i);
              try {
                   Thread.sleep(200);
              } catch (final InterruptedException e) {
                   e.printStackTrace();
              }
         }
    }
}

第2步:让我们创建newFixedThreadPool() 方法,用两个线程执行5个任务。

public class FixedThreadPoolExample {
 
     public static void main(final String[] args) throws InterruptedException, ExecutionException {
  
          System.out.println("Thread main started");
  
          final ExecutorService executorService = Executors.newFixedThreadPool(2);
          executorService.execute(new Task());
          executorService.execute(new Task());
          executorService.execute(new Task());
          executorService.execute(new Task());
          executorService.execute(new Task());
  
          executorService.shutdown();
  
          System.out.println("Thread main finished");
     }
}

输出。

Thread main started
[pool-1-thread-1] Message 0
[pool-1-thread-2] Message 0
Thread main finished
[pool-1-thread-1] Message 1
[pool-1-thread-2] Message 1
[pool-1-thread-1] Message 2
[pool-1-thread-2] Message 2
[pool-1-thread-1] Message 3
[pool-1-thread-2] Message 3
[pool-1-thread-2] Message 4
[pool-1-thread-1] Message 4
[pool-1-thread-1] Message 0
[pool-1-thread-2] Message 0
[pool-1-thread-1] Message 1
[pool-1-thread-2] Message 1
[pool-1-thread-1] Message 2
[pool-1-thread-2] Message 2
[pool-1-thread-1] Message 3
[pool-1-thread-2] Message 3
[pool-1-thread-1] Message 4
[pool-1-thread-2] Message 4
[pool-1-thread-1] Message 0
[pool-1-thread-1] Message 1
[pool-1-thread-1] Message 2
[pool-1-thread-1] Message 3
[pool-1-thread-1] Message 4

我们使用了新的newFixedThreadPool,所以当我们提交了5个任务后,将创建2个新的线程并执行2个任务。其他3个任务将在一个等待队列中等待。只要一个线程完成了任何任务,另一个任务就会被这个线程选中并执行。

2. Executors.newSingleThreadExecutor() 方法

这个方法创建了一个Executor ,它使用一个单一的工作线程,从一个无界队列中操作。(但是请注意,如果这个单线程在关机前的执行过程中由于故障而终止,如果需要执行后续的任务,一个新的线程将取代它的位置。) 任务被保证按顺序执行,并且在任何时候都不会有超过一个任务处于活动状态。与其他同等的newFixedThreadPool(1) 不同,返回的执行器被保证不能被重新配置以使用额外的线程。

请注意,Executors.newSingleThreadExecutor() 方法返回新创建的单线程执行器。
语法。

ExecutorService executorService = Executors.newSingleThreadExecutor();

Executors.newSingleThreadExecutor() 方法示例

在这个例子中,我们用一个单线程实例化了一个线程池。所有的任务都由同一个线程按顺序执行。

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

//*
/* Instantiates a thread pool with a single thread
/* All tasks are executed sequentially by the same thread
/*/

public class SingleThreadPoolExample {

    public static void main(String[] args) throws InterruptedException, ExecutionException {

        System.out.println("Thread main started");

        Runnable task1 = () -> {
             System.out.println("Executing Task1 inside : " + Thread.currentThread().getName());
             try {
                 TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException ex) {
                 throw new IllegalStateException(ex);
            }
        };

        Runnable task2 = () -> {
             System.out.println("Executing Task2 inside : " + Thread.currentThread().getName());
             try {
                  TimeUnit.SECONDS.sleep(4);
             } catch (InterruptedException ex) {
                  throw new IllegalStateException(ex);
             }
        };

        Runnable task3 = () -> {
             System.out.println("Executing Task3 inside : " + Thread.currentThread().getName());
            try {
                 TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException ex) {
                 throw new IllegalStateException(ex);
            }
       };

       final ExecutorService executorService = Executors.newSingleThreadExecutor();
       System.out.println("Submitting the tasks for execution...");
       executorService.submit(task1);
       executorService.submit(task2);
       executorService.submit(task3);

       executorService.shutdown();

       System.out.println("Thread main finished");
    }
}

输出:

Thread main started
Submitting the tasks for execution...
Executing Task1 inside : pool-1-thread-1
Thread main finished
Executing Task2 inside : pool-1-thread-1
Executing Task3 inside : pool-1-thread-1

我们使用了newSingleThreadExecutor,所以当我们提交了3个任务后,将创建一个新的线程,并一次执行一个任务。其他两个任务将在一个等待队列中等待。一旦一个线程完成了一个任务,另一个任务就会被这个线程选中并执行。

3. Executors.newCachedThreadPool() 方法

这个方法创建了一个线程池,它可以根据需要创建新的线程,但当之前构建的线程可用时,它将重新使用。这些线程池通常会提高执行许多短暂的异步任务的程序的性能。

对执行的调用将重用先前构建的线程,如果可用的话。如果没有现有的线程可用,将创建一个新的线程并添加到池中。六十秒内未被使用的线程将被终止并从缓存中删除。因此,一个池子如果保持足够长的空闲时间,就不会消耗任何资源。请注意,具有类似属性但细节不同(例如,超时参数)的池可以使用ThreadPoolExecutor 构造函数来创建。
语法。

final ExecutorService executorService = Executors.newCachedThreadPool();

Executors.newCachedThreadPool() 方法示例

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

public class CachedThreadPoolExample {

    public static void main(final String[] args) throws InterruptedException, ExecutionException {

        System.out.println("Thread main started");

        Runnable task1 = () -> {
             System.out.println("Executing Task1 inside : " + Thread.currentThread().getName());
             try {
                  TimeUnit.SECONDS.sleep(2);
             } catch (InterruptedException ex) {
                  throw new IllegalStateException(ex);
             }
        };

        Runnable task2 = () -> {
             System.out.println("Executing Task2 inside : " + Thread.currentThread().getName());
             try {
                  TimeUnit.SECONDS.sleep(4);
             } catch (InterruptedException ex) {
                  throw new IllegalStateException(ex);
             }
       };

        Runnable task3 = () -> {
            System.out.println("Executing Task3 inside : " + Thread.currentThread().getName());
            try {
                 TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException ex) {
                 throw new IllegalStateException(ex);
            }
        };

        final ExecutorService executorService = Executors.newCachedThreadPool();
        System.out.println("Submitting the tasks for execution...");
        executorService.submit(task1);
        executorService.submit(task2);
        executorService.submit(task3);

        executorService.shutdown();

        System.out.println("Thread main finished");
    }
}

输出。

Thread main started
Submitting the tasks for execution...
Executing Task1 inside : pool-1-thread-1
Executing Task3 inside : pool-1-thread-3
Executing Task2 inside : pool-1-thread-2
Thread main finished

4. Executors.newScheduledThreadPool方法

该方法创建了一个线程池,可以安排命令在给定的延迟后运行或定期执行。

newScheduledThreadPool方法返回ScheduledExecutorService 接口
ScheduledExecutorService接口提供 schedule()方法创建具有各种延迟的任务,并返回一个可用于取消或检查执行的任务对象。scheduleAtFixedRate()scheduleWithFixedDelay()方法创建并执行周期性运行的任务,直到取消。

使用Executor.execute(Runnable)ExecutorService 提交方法提交的命令以要求的延迟为零来安排。在schedule方法中也允许零和负延迟(但不是周期),并被视为立即执行的请求。
让我们通过一个例子来理解ScheduledExecutorService 界面和newScheduledThreadPool()工厂方法的方法。

public class SchedulingTasksWithScheduledThreadPool {

    public static void main(String[] args) throws InterruptedException {
        System.out.println("Thread main started");

        // Create a task
        Runnable task1 = () -> {
            System.out.println("Executing the task1 at: " + new Date());
        };

         // Create a task
        Runnable task2 = () -> {
            System.out.println("Executing the task2 at: " + new Date());
        };
 
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);

        System.out.println("Scheduling task to run after 5 seconds... " + new Date());
        scheduledExecutorService.schedule(task1, 5, TimeUnit.SECONDS);
        scheduledExecutorService.schedule(task2, 5, TimeUnit.SECONDS);

        scheduledExecutorService.shutdown();
        System.out.println("Thread main finished");
    }
}

输出:

Thread main started
Scheduling task to run after 5 seconds... Sat Sep 01 10:56:40 IST 2018
Thread main finished
Executing the task1 at: Sat Sep 01 10:56:45 IST 2018
Executing the task2 at: Sat Sep 01 10:56:45 IST 2018

*scheduledExecutorService.schedule()*函数接收一个Runnable,一个延迟值,以及延迟的单位。上面的程序在提交后的5秒后执行任务。
现在让我们看一个例子,我们定期执行任务 -

public class SchedulingTasksWithScheduledThreadPool {

    public static void main(String[] args) throws InterruptedException {
        System.out.println("Thread main started");

        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);

        // Create a task
        Runnable task1 = () -> {
            System.out.println("Executing the task1 at: " + new Date());
        };

        scheduledExecutorService.scheduleAtFixedRate(task1, 0, 2, TimeUnit.SECONDS);

        System.out.println("Thread main finished");
    }
}

输出:

Thread main started
Thread main finished
Executing the task1 at: Sat Sep 01 11:03:16 IST 2018
Executing the task1 at: Sat Sep 01 11:03:18 IST 2018
Executing the task1 at: Sat Sep 01 11:03:20 IST 2018
Executing the task1 at: Sat Sep 01 11:03:22 IST 2018
Executing the task1 at: Sat Sep 01 11:03:24 IST 2018
......

注意,如果任务遇到异常,任务的后续执行会被抑制。否则,只有当你关闭执行器或杀死程序时,该任务才会终止。

5. Executors.newSingleThreadScheduledExecutor() 方法

这个方法创建了一个单线程的执行器,它可以安排命令在给定的延迟后运行或定期执行。(但是请注意,如果这个单线程在关机前的执行过程中由于故障而终止,如果需要执行后续的任务,一个新的线程将取代它的位置。) 任务被保证按顺序执行,并且在任何时候都不会有超过一个任务处于活动状态。与其他相等的newScheduledThreadPool(1)不同,返回的执行器被保证不能被重新配置以使用额外的线程。

语法。

ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();

Executors.newSingleThreadScheduledExecutor() 方法示例

import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ExecutorsDemo {

    public static void main(String[] args) {
        ExecutorsDemo demo = new ExecutorsDemo();
        demo.newSingleThreadScheduledExecutor();
    }

    private void newSingleThreadScheduledExecutor() {
        System.out.println("Thread main started");

        ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();

        // Create a task
        Runnable task1 = () -> {
            System.out.println("Executing the task1 at: " + new Date());
        };

        scheduledExecutorService.scheduleAtFixedRate(task1, 0, 2, TimeUnit.SECONDS);

        System.out.println("Thread main finished");
    }
}

输出。

Thread main started
Thread main finished
Executing the task1 at: Mon Sep 10 13:15:57 IST 2018
Executing the task1 at: Mon Sep 10 13:15:59 IST 2018
Executing the task1 at: Mon Sep 10 13:16:01 IST 2018
Executing the task1 at: Mon Sep 10 13:16:03 IST 2018
Executing the task1 at: Mon Sep 10 13:16:05 IST 2018
Executing the task1 at: Mon Sep 10 13:16:07 IST 2018
...............

在Java多线程教程中学习多线程在Java并发性教程中学习高级并发性 

相关文章