您的位置:

JAVA线程池使用实例

一、JAVA线程池使用

在使用Java多线程时引入线程池技术可以大大提高程序性能。Java提供的线程池相关的类主要有四个:Executor、ExecutorService、ScheduledExecutorService和ThreadPoolExecutor。其中,使用ThreadPoolExecutor类可以对线程池进行灵活的设置,可以很好地适应各种场景。

二、JAVA线程池参数设置

在使用Java线程池时,可以根据实际情况对线程池进行参数设置,以达到最佳的程序性能。线程池的主要参数包括以下几个方面:

1、corePoolSize

核心池大小,即线程池初始化后启动的线程数量。如果当前线程数量小于核心池大小,则新建线程;否则会将任务放入任务队列等待执行。

2、maximumPoolSize

最大线程数量,即线程池中最多同时执行的线程数量。当线程池中已有的线程数大于等于corePoolSize时,新任务到来时会将任务放入任务队列中等待。当任务到来时任务队列已满且当前线程数小于maximumPoolSize,则新建线程执行该任务。当线程数已达到最大线程数且任务队列已满,则会根据所设置的RejectedExecutionHandler进行相应的拒绝处理。

3、keepAliveTime

线程空闲时间,即空闲线程的存活时间。当线程池中线程数量大于corePoolSize时,需要有一定的机制来回收空闲线程,以便于释放系统资源。当空闲时间超过keepAliveTime时,空闲线程将被回收。

4、TimeUnit

空闲时间的时间单位。该项参数以TimeUnit枚举类型传入,可以设置为TimeUnit.SECONDS、TimeUnit.MINUTES、TimeUnit.HOURS等。

5、workQueue

任务队列。当线程池中线程数量达到corePoolSize时,新任务到来会被放入任务队列中。该任务队列可以是SynchronousQueue、LinkedBlockingQueue、ArrayBlockingQueue等各种线程安全队列,也可以根据需要自己实现。

6、threadFactory

线程工厂。用于创建新的线程对象。可以通过ThreadFactoryBuilder来创建一个线程工厂。

7、rejectedExecutionHandler

任务拒绝策略。当线程池中线程数量已达到maximumPoolSize并且任务队列已经满了时,需要有一种机制来处理新到达的任务。主要有四种处理方式:

  • AbortPolicy(默认):直接抛出RejectedExecutionException异常。
  • CallerRunsPolicy:任务由调用线程直接执行。
  • DiscardOldestPolicy:将等待时间最长的任务从队列中移除,将新任务加入队列中。
  • DiscardPolicy:直接丢弃该任务。

三、JAVA创建线程池

Java提供了四个线程池类,分别是:

  • FixedThreadPool
  • CachedThreadPool
  • SingleThreadExecutor
  • ScheduledThreadPool

1、FixedThreadPool

FixedThreadPool固定大小线程池,会一直新建线程直到线程达到线程池的最大大小,线程池中的线程都是活跃的,线程池中线程数量不会超过给定的数量,并且线程都是在空闲状态下等待接收任务,所以线程利用率高。

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue());
}

  

2、CachedThreadPool

CachedThreadPool线程池的大小会根据执行的任务数量自动扩展和收缩,没有核心线程数,超过60秒空闲的线程被终止并从缓冲池中删除。适用于执行大量短期异步任务的情景。

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue());
}

  

3、SingleThreadExecutor

SingleThreadExecutor单线程池中只有一个核心线程,该线程会按先进先出的方式执行任务,所以不需要考虑线程同步的问题。适用于需要排队依次执行任务的情况。

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue()));
}

  

4、ScheduledThreadPool

ScheduledThreadPool定长线程池可以定时或周期性地执行任务。适用于需要执行定时任务的情况。

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}

完整的Java线程池使用实例:

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

public class ThreadPoolTest {

    public static void main(String[] args) throws Exception {

        ExecutorService executorService = Executors.newFixedThreadPool(2);

        executorService.execute(() -> {
            System.out.println("任务1开始执行");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("任务1执行完毕");
        });

        executorService.execute(() -> {
            System.out.println("任务2开始执行");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("任务2执行完毕");
        });

        executorService.execute(() -> {
            System.out.println("任务3开始执行");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("任务3执行完毕");
        });

        executorService.shutdown();
        executorService.awaitTermination(1, TimeUnit.HOURS);

    }

}