Java线程池-ThreadPoolExecutor,Executors使用示例

1. Executors简单示例

java提供了Executors线程池创建工具方便我们创建合适的线程池,示例如下,提供了四种创建线程池的简单方法,当然,其中有各自的优劣,之后 再叙述。

//创建一个会根据需要自动创建线程的线程池,并且有空闲线程存在时,不再创建新的线程,将重用该空闲线城池
ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); 
//创建并保持固定数量的线程池
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);
//利用主机上可用处理器的数量作为目标并行级别,创建一个基于工作-窃取算法的线程池
ExecutorService workStealingPool = Executors.newWorkStealingPool();
//创建一个线程池,可以调度命令在指定延迟后运行或周期性执行
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10);

接下来,根据上面java提供的简单方法创建一个CachedThreadPool简单的示例。

public class CachedTheadPoolDemo {

    public static void main(String[] args){
        // 创建线程池
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        // 创建3个线程
        for (int i = 0; i < 3; i++) {
            CustomTask customTask = new CustomTask(i + "");
            cachedThreadPool.execute(customTask);
        }
    }
}

// 自定义一个任务
class CustomTask extends Thread {

    private String taskName;

    public CustomTask(String taskName){
        this.taskName = taskName;
    }
    @Override
    public void run() {
        // 循环打印出任务名和标签
        for (int i = 0; i < 3; i++) {
            System.out.println("Task: "+taskName+", Tag: "+i);
        }
    }
}

运行结果如下,

Task: 0, Tag: 0
Task: 1, Tag: 0
Task: 2, Tag: 0
Task: 1, Tag: 1
Task: 0, Tag: 1
Task: 1, Tag: 2
Task: 2, Tag: 1
Task: 0, Tag: 2
Task: 2, Tag: 2

2. ThreadPoolExecutor简单示例

在阿里巴巴java开发规范手册中,并不推荐使用Executors工具去创建线程池,而是使用ThreadPoolExecutor创建线程池至于原因,在下面再讨论。那么,先看看ThreadPoolExecutor是怎么创建线程池的,示例如下

import java.util.concurrent.*;

public class ThreadPoolExecutorDemo {

    public static void main(String[] args){

        int corePoolSize = 4;  // 一直保持在线程池内的线程数量,这个数量内的线程就算空闲也不会被回收,除非设置了allowCoreThreadTimeOut
        int maximumPoolSize = 8; // 线程池允许持有的最大线程数量
        long keepAliveTime = 10; // 当线程数量大于核心线程数量(corePoolSize)时,回收空闲线程的最大时间
        TimeUnit unit = TimeUnit.SECONDS; // keepAliveTime的时间单位
        BlockingQueue<Runnable> workQueue = new LinkedBlockingDeque<>(4); // 保存被执行前任务的队列,这个队列只会保存被execute方法提交的Runnable任务
        ThreadFactory threadFactory = Executors.defaultThreadFactory(); // 创建线程的工厂类
        RejectedExecutionHandler rejectedPolicy = new ThreadPoolExecutor.AbortPolicy(); // 当线程阻塞并且达到任务队列最大容量时调用的处理器

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, rejectedPolicy);
        for (int i = 0; i < 3; i++) {
            CustomTask customTask = new CustomTask(i + "");
            threadPoolExecutor.execute(customTask);
        }

    }
}

class CustomTask extends Thread {

    private String taskName;

    public CustomTask(String taskName){
        this.taskName = taskName;
    }
    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println("Task: "+taskName+", Tag: "+i);
        }
    }
}

控制台输出结果,

Task: 2, Tag: 0
Task: 1, Tag: 0
Task: 0, Tag: 0
Task: 1, Tag: 1
Task: 2, Tag: 1
Task: 1, Tag: 2
Task: 0, Tag: 1
Task: 2, Tag: 2
Task: 0, Tag: 2

 

3. Executors源码分析

在第1节中,以及了解到了Executors线程池创建工具的简单使用,那么这一节将从源码的角度去看待各种创建方法的不同。

3.1 CachedThreadPool

// 创建一个可以根据需要创建新线程的线程池
public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                   new SynchronousQueue<Runnable>());
}

定义Executors调用newCachedThreadPool()方法创建一个线程池,该线程池的核心线程数为0,线程池可持有的最大线程数为Integer类型的最大值2^{31}-1,回收空闲线程的等待时间为60秒,采用阻塞队列保存任务(Task)。

 

3.2 FixedThreadPool

// 创建一个保存固定线程数量的线程池
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

定义Executors调用newFixedThreadPool(int nThreads)方法创建一个核心线程数量和线程数量相同的线程池,采用基于linked nodes的可选非阻塞队列保存任务,队列初始容量为Integer类型的最大值2^{31}-1

3.3 WorkStealingThreadPool

//用可用处理器数量作为目标并行级别创建一个work-stealing的线程池
public static ExecutorService newWorkStealingPool() {
    return new ForkJoinPool
         (Runtime.getRuntime().availableProcessors(),
          ForkJoinPool.defaultForkJoinWorkerThreadFactory,
          null, true);
}

定义: Executors调用newWorkStealingPool()方法创建一个线程池,该线程池为ForkJoinPool线程池,继承了AbstractExecutorService,使用DefaultForkJoinWorkerThreadFactory作为默认创建新线程的工厂类,默认对内部工作线程执行任务出现不可恢复错误时不做任何处理,并为未加入的forked task建立本地先进先出的任务调度模式。

3.4 ScheduledThreadPool

// Executors中,传入核心线程数调用ScheduledThreadPool的构造函数,创建线程池
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
   return new ScheduledThreadPoolExecutor(corePoolSize);
}




// ScheduledThreadPoolExecutor中构造函数,创建一个线程池
public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE,
              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
              new DelayedWorkQueue());
    }

定义: Executors调用newScheduledThreadPool方法时,会间接调用ScheduledThreadPoolExecutor的构造函数创建线程池,该线程池核心线程数为corePoolSize,可持有的最大线程数为Integer类型的最大值2^{31}-1,回收空闲线程的默认时间为10毫秒,采用一个专门的延迟队列,该队列也为阻塞队列,初始容量为16。

Java线程池ThreadPoolExecutorJava提供的一个用于管理和复用线程的工具类。它可以帮助我们更有效地管理线程资源,提高程序的性能和可维护性。 下面是一个简单的使用ThreadPoolExecutor示例代码: ```java import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPoolExample { public static void main(String[] args) { // 创建一个线程池,其中包含5个线程 ExecutorService executor = Executors.newFixedThreadPool(5); // 提交任务给线程池执行 for (int i = 0; i < 10; i++) { Runnable worker = new WorkerThread("Task " + i); executor.execute(worker); } // 关闭线程池 executor.shutdown(); while (!executor.isTerminated()) { // 等待所有任务完成 } System.out.println("所有任务已完成"); } } class WorkerThread implements Runnable { private String taskName; public WorkerThread(String taskName) { this.taskName = taskName; } @Override public void run() { System.out.println(Thread.currentThread().getName() + " 开始执行任务:" + taskName); try { // 模拟任务执行时间 Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 完成任务:" + taskName); } } ``` 上述代码中,首先通过`Executors.newFixedThreadPool(5)`创建了一个包含5个线程的线程池。然后使用`executor.execute(worker)`提交任务给线程池执行,其中`worker`是实现了`Runnable`接口的任务对象。任务会被线程池中的线程异步执行。 最后,通过`executor.shutdown()`关闭线程池,并使用`executor.isTerminated()`等待所有任务完成。完成后输出"所有任务已完成"。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值