专业的JAVA编程教程与资源

网站首页 > java教程 正文

Java 线程池规范使用示例

temp10 2025-05-23 20:00:36 java教程 1 ℃ 0 评论

1 摘要

Java 线程池在批量处理的场景中应用广泛。常见的四种创建线程池的方法:newSingleThreadExecutor,newFixedThreadPool,newCachedThreadPool,newScheduledThreadPool,各有各的缺陷,不建议使用。本文将给出根据阿里巴巴Java开发手册推荐的方式创建线程池的示例。

Java 线程池规范使用示例

2 推荐创建线程池的方法

java.util.concurrent.ThreadPoolExecutor

ThreadPoolExecutor(int corePoolSize,

int maximumPoolSize,

long keepAliveTime,

TimeUnit unit,

BlockingQueue<Runnable> workQueue,

ThreadFactory threadFactory,

RejectedExecutionHandler handler)

参数说明:

corePoolSize: 线程池核心线程数量,推荐为服务器的核心数量

maximumPoolSize: 线程池最大线程数量,推荐为和服务核心数量的两倍

keepAliveTime: 线程销毁等待时间,当线程数超过核心线程数量(corePoolSize)时,销毁多余线程需要等待的最大时间;可根据任务执行的频率设置时间长度

unit: 线程销毁等待时间单位,有毫秒,秒,小时等

workQueue: 工作负载阻塞队列,当线程池中线程数量达到最大值时,仍然有未处理的任务,此时会将任务放在该队列中

threadFactory: 线程工厂,用于创建线程

RejectedExecutionHandler: 线程池拒绝策略,当线程数量达到线程池最大值,工作负载队列满了之后,线程池对于新任务的处理策略。有四种:


java.util.concurrent.ThreadPoolExecutor.AbortPolicy: 抛出异常,不作处理


java.util.concurrent.ThreadPoolExecutor.DiscardPolicy: 丢弃新任务,也不抛出异常


java.util.concurrent.ThreadPoolExecutor.DiscardOldestPolicy: 丢弃最老的任务


java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy: 把任务交给调用线程池的线程处理,直到线程池死了


通常情况下选择抛出异常的策略即可。

3 核心示例代码

3.1 任务负载

./src/main/java/com/ljq/demo/concurrent/DrinkTask.java

1

package com.ljq.demo.concurrent;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Callable;

/**

* @Description: 喝酒任务

* @Author: junqiang.lu

* @Date: 2021/5/14

*/

@Slf4j

public class DrinkTask implements Callable<Integer> {

/**

* 当前杯数

*/

private int cupNumber;

public DrinkTask(int cupNumber) {

this.cupNumber = cupNumber;

}

@Override

public Integer call() throws Exception {

log.info("武松喝完了第[" + cupNumber + "]杯酒");

Thread.sleep(100);

return cupNumber;

}

}

3.2 简易线程池工具类

./src/main/java/com/ljq/demo/util/ThreadPoolUtil.java

1

package com.ljq.demo.util;

import cn.hutool.core.thread.ThreadFactoryBuilder;

import java.util.concurrent.*;

/**

* @Description: 线程池工具类

* @Author: junqiang.lu

* @Date: 2021/5/14

*/

public class ThreadPoolUtil {

private ThreadPoolUtil(){

}

static {

initExecutor();

}

/**

* 线程池执行器

*/

private static transient ThreadPoolExecutor executor;

/**

* 执行任务

* (不包含返回值)

*

* @param command

*/

public static void execute(Runnable command) {

executor.execute(command);

}

/**

* 执行任务

* (包含返回值)

*

* @param task

* @param <T>

* @return

*/

public static <T> Future<T> executeAsync(Callable<T> task) {

return executor.submit(task);

}

/**

* 销毁线程池

*/

public static void shutdown() {

executor.shutdown();

}

/**

* 初始化线程池

*/

private static void initExecutor() {

if (executor == null || executor.isShutdown()) {

synchronized (ThreadPoolUtil.class) {

if (executor == null || executor.isShutdown()) {

executor = new ThreadPoolExecutor(4,10,100,

TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(1000),

ThreadFactoryBuilder.create().build(), new ThreadPoolExecutor.AbortPolicy());

}

}

}

}

}

3.3 线程池运行测试示例

./src/main/java/com/ljq/demo/concurrent/DrinkThreadPoolDemo.java

1

package com.ljq.demo.concurrent;

import cn.hutool.core.thread.ThreadFactoryBuilder;

import cn.hutool.core.thread.ThreadUtil;

import com.ljq.demo.util.ThreadPoolUtil;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ArrayBlockingQueue;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.ThreadPoolExecutor;

import java.util.concurrent.TimeUnit;

/**

* @Description: 喝酒线程池示例

* @Author: junqiang.lu

* @Date: 2021/5/14

*/

@Slf4j

public class DrinkThreadPoolDemo {

public static void main(String[] args) {

manualThreadPool();

huToolThreadUtil();

localThreadPoolUtil();

}

/**

* 手动创建线程池

*/

public static void manualThreadPool() {

// 创建线程池

ThreadPoolExecutor executor = new ThreadPoolExecutor(2,10,100,

TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(1000), ThreadFactoryBuilder.create().build(),

new ThreadPoolExecutor.AbortPolicy());

// 总杯数

int totalCup = 100;

int cupNumber;

for (int i = 1; i <= totalCup; i++) {

try {

cupNumber = executor.submit(new DrinkTask(i)).get();

log.info("manual cupNumber: {}", cupNumber);

} catch (InterruptedException e) {

log.error("线程池执行错误", e);

} catch (ExecutionException e) {

log.error("武松喝醉了", e);

}

}

// 关闭线程池

executor.shutdown();

}

/**

* 使用 hutool 线程工具类

* (线程池不会自动销毁)

*/

public static void huToolThreadUtil() {

// 总杯数

int totalCup = 100;

int cupNumber;

for (int i = 1; i <= totalCup; i++) {

try {

cupNumber = ThreadUtil.execAsync(new DrinkTask(i)).get();

log.info("hutool cupNumber: {}", cupNumber);

} catch (InterruptedException e) {

log.error("线程池执行错误", e);

} catch (ExecutionException e) {

log.error("武松喝醉了", e);

}

}

}

/**

* 本地线程池工具类

*/

public static void localThreadPoolUtil() {

// 总杯数

int totalCup = 100;

int cupNumber;

for (int i = 1; i <= totalCup; i++) {

try {

cupNumber = ThreadPoolUtil.executeAsync(new DrinkTask(i)).get();

log.info("local cupNumber: {}", cupNumber);

} catch (InterruptedException e) {

log.error("线程池执行错误", e);

} catch (ExecutionException e) {

log.error("武松喝醉了", e);

}

}

ThreadPoolUtil.shutdown();

}

}

3.4 部分执行日志

2021-05-14 16:50:58:890 [pool-4-thread-1] INFO
com.ljq.demo.concurrent.DrinkTask(DrinkTask.java 26) -武松喝完了第[1]杯酒

2021-05-14 16:50:58:992 [main] INFO com.ljq.demo.concurrent.DrinkThreadPoolDemo(DrinkThreadPoolDemo.java 82) -local cupNumber: 1

2021-05-14 16:50:58:993 [pool-4-thread-2] INFO
com.ljq.demo.concurrent.DrinkTask(DrinkTask.java 26) -武松喝完了第[2]杯酒

2021-05-14 16:50:59:094 [main] INFO com.ljq.demo.concurrent.DrinkThreadPoolDemo(DrinkThreadPoolDemo.java 82) -local cupNumber: 2

2021-05-14 16:50:59:095 [pool-4-thread-3] INFO
com.ljq.demo.concurrent.DrinkTask(DrinkTask.java 26) -武松喝完了第[3]杯酒

2021-05-14 16:50:59:199 [main] INFO com.ljq.demo.concurrent.DrinkThreadPoolDemo(DrinkThreadPoolDemo.java 82) -local cupNumber: 3

2021-05-14 16:50:59:200 [pool-4-thread-4] INFO
com.ljq.demo.concurrent.DrinkTask(DrinkTask.java 26) -武松喝完了第[4]杯酒

2021-05-14 16:50:59:301 [main] INFO com.ljq.demo.concurrent.DrinkThreadPoolDemo(DrinkThreadPoolDemo.java 82) -local cupNumber: 4

2021-05-14 16:50:59:301 [pool-4-thread-1] INFO
com.ljq.demo.concurrent.DrinkTask(DrinkTask.java 26) -武松喝完了第[5]杯酒

2021-05-14 16:50:59:401 [main] INFO com.ljq.demo.concurrent.DrinkThreadPoolDemo(DrinkThreadPoolDemo.java 82) -local cupNumber: 5

... ...

2021-05-14 16:51:08:694 [pool-4-thread-4] INFO
com.ljq.demo.concurrent.DrinkTask(DrinkTask.java 26) -武松喝完了第[96]杯酒

2021-05-14 16:51:08:794 [main] INFO com.ljq.demo.concurrent.DrinkThreadPoolDemo(DrinkThreadPoolDemo.java 82) -local cupNumber: 96

2021-05-14 16:51:08:795 [pool-4-thread-1] INFO
com.ljq.demo.concurrent.DrinkTask(DrinkTask.java 26) -武松喝完了第[97]杯酒

2021-05-14 16:51:08:897 [main] INFO com.ljq.demo.concurrent.DrinkThreadPoolDemo(DrinkThreadPoolDemo.java 82) -local cupNumber: 97

2021-05-14 16:51:08:897 [pool-4-thread-2] INFO
com.ljq.demo.concurrent.DrinkTask(DrinkTask.java 26) -武松喝完了第[98]杯酒

2021-05-14 16:51:08:998 [main] INFO com.ljq.demo.concurrent.DrinkThreadPoolDemo(DrinkThreadPoolDemo.java 82) -local cupNumber: 98

2021-05-14 16:51:08:999 [pool-4-thread-3] INFO
com.ljq.demo.concurrent.DrinkTask(DrinkTask.java 26) -武松喝完了第[99]杯酒

2021-05-14 16:51:09:101 [main] INFO com.ljq.demo.concurrent.DrinkThreadPoolDemo(DrinkThreadPoolDemo.java 82) -local cupNumber: 99

2021-05-14 16:51:09:102 [pool-4-thread-4] INFO
com.ljq.demo.concurrent.DrinkTask(DrinkTask.java 26) -武松喝完了第[100]杯酒

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表