Java 简明教程

Java - Thread Pools

Thread Pools

线程池是预初始化的 threads 集合。线程池背后的总体计划是在方法启动时形成各种线程,并将它们放入池中,它们在池中等待工作。一旦服务器收到参与请求,便会唤醒此池中的一个线程(如果可用),并向它传递服务请求。一旦线程完成服务,它便会返回池中,等待更多工作。如果池中没有可访问的线程,则服务器会等待,直到一个线程变为可用。

Why Use Thread Pools in Java?

  1. 它可以节省时间,因为没有必要生成新线程。

  2. 它用于 ServletJSP,无论何时设备创建一个线程池以方式请求。

Creating Thread Pools in Java

Java 提供了*java.util.concurrent.Executors*类,它提供了一些方法来创建线程池。

Executors Class Methods

以下是此类中创建线程池的一些重要且有用的方法:

Sr.No.

Method & Description

1

public static ExecutorService newCachedThreadPool() 根据需要创建新线程的线程池,但当先前构造的线程可用时会重用这些线程。

2

public static ExecutorService newFixedThreadPool(int nThreads) 创建重用固定数量线程的线程池,并且这些线程从共享的无界队列中运行。

3

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) 创建线程池,该线程池可安排命令在给定的延迟后或定期执行。

4

public static ExecutorService newWorkStealingPool() 创建工作窃取线程池,使用所有可用处理器作为其目标并行级别。

Creating a Thread Pool Using newFixedThreadPool() Method

可变线程池通过调用 Executor 类的新建 static newFixedThreadPool() 方法获得。

Syntax

ExecutorService fixedPool = Executors.newFixedThreadPool(2);

其中,

  1. 最多有 2 个线程激活以处理任务。

  2. 如果提交的线程超过 2 个,则将它们保存在队列中,直到线程变为可用。

  3. 如果线程因为执行期间的故障而终止,则会创建新线程以取代它(尚未调用执行器的关闭)。

  4. 任何线程在池关闭之前都会存在。

Example: Creating a Thread Pool Using newFixedThreadPool() Method

下面的 TestThread 程序演示了使用 Execution 的 newFixedThreadPool() 方法来创建包含两个线程的线程池。我们正在使用 ThreadPoolExecutor 对象,并用 newFixedThreadPool(2) 初始化,一个大小为 2 的固定线程池。然后我们正在打印线程池的各种属性。然后我们向执行器中添加一些线程,然后打印线程池的相同属性以反映更改。

package com.tutorialspoint;

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

public class TestThread {

   public static void main(final String[] arguments) throws InterruptedException {
      ExecutorService executor = Executors.newFixedThreadPool(2);

      // Cast the object to its class type
      ThreadPoolExecutor pool = (ThreadPoolExecutor) executor;

      //Stats before tasks execution
      System.out.println("Largest executions: "
         + pool.getLargestPoolSize());
      System.out.println("Maximum allowed threads: "
         + pool.getMaximumPoolSize());
      System.out.println("Current threads in pool: "
         + pool.getPoolSize());
      System.out.println("Currently executing threads: "
         + pool.getActiveCount());
      System.out.println("Total number of threads(ever scheduled): "
         + pool.getTaskCount());

      executor.submit(new Task());
      executor.submit(new Task());
	  executor.submit(new Task());
      executor.submit(new Task());

      //Stats after tasks execution
      System.out.println("Core threads: " + pool.getCorePoolSize());
      System.out.println("Largest executions: "
         + pool.getLargestPoolSize());
      System.out.println("Maximum allowed threads: "
         + pool.getMaximumPoolSize());
      System.out.println("Current threads in pool: "
         + pool.getPoolSize());
      System.out.println("Currently executing threads: "
         + pool.getActiveCount());
      System.out.println("Total number of threads(ever scheduled): "
         + pool.getTaskCount());

      executor.shutdown();
   }

   static class Task implements Runnable {

      public void run() {

         try {
            Long duration = (long) (Math.random() * 5);
            System.out.println("Running Task! Thread Name: " +
               Thread.currentThread().getName());
               TimeUnit.SECONDS.sleep(duration);

            System.out.println("Task Completed! Thread Name: " +
               Thread.currentThread().getName());
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
   }
}
Largest executions: 0
Maximum allowed threads: 2
Current threads in pool: 0
Currently executing threads: 0
Total number of threads(ever scheduled): 0
Core threads: 2
Largest executions: 2
Maximum allowed threads: 2
Current threads in pool: 2
Currently executing threads: 2
Total number of threads(ever scheduled): 4
Running Task! Thread Name: pool-1-thread-2
Running Task! Thread Name: pool-1-thread-1
Task Completed! Thread Name: pool-1-thread-2
Running Task! Thread Name: pool-1-thread-2
Task Completed! Thread Name: pool-1-thread-1
Running Task! Thread Name: pool-1-thread-1
Task Completed! Thread Name: pool-1-thread-2
Task Completed! Thread Name: pool-1-thread-1

尽管在这里我们提交了四次线程,但只执行了两个线程,因为线程池被固定为仅接受两个线程。

Creating a Thread Pool Using newCachedThreadPool() Method

可以通过调用 Executors 类的静态 newCachedThreadPool() 方法获得缓存的线程池。

Syntax

ExecutorService executor = Executors.newCachedThreadPool();

其中,

  1. newCachedThreadPool 方法创建拥有可扩展线程池的执行器。

  2. 这种执行器适合于启动许多短生存期任务的应用程序。

Example: Creating a Thread Pool Using newCachedThreadPool() Method

TestThread 程序展示了 Executor newCachedThreadPool() 方法的使用,它用来创建一个可扩展的线程池。我们使用了 ThreadPoolExecutor 对象,并使用 newCachedThreadPool() 初始化。然后,我们将打印线程池的各种属性。然后,我们向执行器添加几个线程,接着打印线程池的相同属性以反映更改。

package com.tutorialspoint;

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

public class TestThread {

   public static void main(final String[] arguments) throws InterruptedException {
      ExecutorService executor = Executors.newCachedThreadPool();

      // Cast the object to its class type
      ThreadPoolExecutor pool = (ThreadPoolExecutor) executor;

      //Stats before tasks execution
      System.out.println("Largest executions: "
         + pool.getLargestPoolSize());
      System.out.println("Maximum allowed threads: "
         + pool.getMaximumPoolSize());
      System.out.println("Current threads in pool: "
         + pool.getPoolSize());
      System.out.println("Currently executing threads: "
         + pool.getActiveCount());
      System.out.println("Total number of threads(ever scheduled): "
         + pool.getTaskCount());

      executor.submit(new Task());
      executor.submit(new Task());
	  executor.submit(new Task());
      executor.submit(new Task());

      //Stats after tasks execution
      System.out.println("Core threads: " + pool.getCorePoolSize());
      System.out.println("Largest executions: "
         + pool.getLargestPoolSize());
      System.out.println("Maximum allowed threads: "
         + pool.getMaximumPoolSize());
      System.out.println("Current threads in pool: "
         + pool.getPoolSize());
      System.out.println("Currently executing threads: "
         + pool.getActiveCount());
      System.out.println("Total number of threads(ever scheduled): "
         + pool.getTaskCount());

      executor.shutdown();
   }

   static class Task implements Runnable {

      public void run() {

         try {
            Long duration = (long) (Math.random() * 5);
            System.out.println("Running Task! Thread Name: " +
               Thread.currentThread().getName());
               TimeUnit.SECONDS.sleep(duration);

            System.out.println("Task Completed! Thread Name: " +
               Thread.currentThread().getName());
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
   }
}
Largest executions: 0
Maximum allowed threads: 2147483647
Current threads in pool: 0
Currently executing threads: 0
Total number of threads(ever scheduled): 0
Core threads: 0
Largest executions: 4
Maximum allowed threads: 2147483647
Current threads in pool: 4
Currently executing threads: 4
Total number of threads(ever scheduled): 4
Running Task! Thread Name: pool-1-thread-2
Running Task! Thread Name: pool-1-thread-4
Running Task! Thread Name: pool-1-thread-3
Running Task! Thread Name: pool-1-thread-1
Task Completed! Thread Name: pool-1-thread-3
Task Completed! Thread Name: pool-1-thread-4
Task Completed! Thread Name: pool-1-thread-2
Task Completed! Thread Name: pool-1-thread-1

Creating a Thread Pool Using newScheduledThreadPool() Method

通过调用 Executor 类的静态 newScheduledThreadPool() 方法获取一个计划线程池。

Syntax

ExecutorService executor = Executors.newScheduledThreadPool(1);

Example: Creating a Thread Pool Using newScheduledThreadPool() Method

TestThread 程序演示了 Executor newScheduledThreadPool() 方法的使用,它用来创建一个线程池。我们使用了一个 ScheduledExecutorService 对象作为计划程序,并使用 newScheduledThreadPool() 进行了初始化。我们还创建了一个 ScheduledFuture 对象,以计划在延迟两秒之后每两秒执行一次任务。使用计划程序,我们将任务计划为连续运行十秒。

package com.tutorialspoint;

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

public class TestThread {

   public static void main(final String[] arguments) throws InterruptedException {
      final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

      final ScheduledFuture<?> beepHandler =
         scheduler.scheduleAtFixedRate(new BeepTask(), 2, 2, TimeUnit.SECONDS);

      scheduler.schedule(new Runnable() {

         @Override
         public void run() {
            beepHandler.cancel(true);
            scheduler.shutdown();
         }
      }, 10, TimeUnit.SECONDS);
   }

   static class BeepTask implements Runnable {

      public void run() {
         System.out.println("beep");
      }
   }
}
beep
beep
beep
beep
beep