【Java】 之 ThreadPoolExecutor 使用案例

Executors 中默认的线程工厂和拒绝策略过于简单,通常对用户不够友好


一、自定义ThreadFactory


对线程池创建的线程必须明确标识,为线程本身指定有意义的名称和相应的序号。

显示调用来源、线程的业务含义,有助于快速定位到死锁、StackOverflowError等问题

如图:
在这里插入图片描述



二、自定义RejectedExecutionHandler


拒绝策略应该考虑到业务场景,返回相应的提示或者友好地跳转。

ThreadPoolExecutor中提供了四个公开的内部静态类:

  1. AbortPolicy(默认): 丢弃任务并抛出RejectedExecutionException异常。
  2. DiscardPolicy: 丢弃任务,但是不抛出异常,这是不推荐的做法。
  3. DiscardOldestPolicy: 抛弃队列中等待最久的任务,然后把当前任务加入队列中。
  4. CallerRunsPolicy: 调用任务的run()方法绕过线程池直接执行。

友好的拒绝策略有:
(1)保存到数据库进行削峰填谷。在空闲时再提取出来执行
(2)转向某个提示页面
(3)打印日志

如图:
在这里插入图片描述



三、测试


如图:
在这里插入图片描述

结果图:

在这里插入图片描述



四、源码


// UserThreadFactory.java
public class UserThreadFactory implements ThreadFactory {

    private final String namePrefix;
    private final AtomicInteger nextId = new AtomicInteger(1);

    // 定义线程组名称,在使用 jstack 来排查线程问题时,非常有帮助
    UserThreadFactory(String whatFeatureOfGroup) {

        this.namePrefix = "UserThreadFactory's " + whatFeatureOfGroup + "-Worker-";
    }

    public Thread newThread(Runnable runnable) {

        String name = this.namePrefix + nextId.getAndIncrement();
        Thread thread = new Thread(null, runnable, name, 0);
        System.out.println(thread.getName());
        return thread;
    }
}

// 任务执行体
class Task implements Runnable {

    private final AtomicLong count = new AtomicLong(0L);

    public void run() {

        System.out.println("running_" + count.getAndIncrement());
    }
}


// UserRejectHandler.java
public class UserRejectHandler implements RejectedExecutionHandler {

    @Override
    public void rejectedExecution(Runnable runnable, ThreadPoolExecutor threadPoolExecutor) {

        System.out.println("task rejected. " + threadPoolExecutor.toString());
    }
}


// UserThreadPool.java
public class UserThreadPool {

    public static void main(String[] args) {

        // 缓存队列设置固定长度为2, 为了快速触发 rejectHandler
        BlockingDeque<Runnable> blockingDeque = new LinkedBlockingDeque<>(2);

        // 假设外部任务线程的来源由机房1 和 机房2的混合调用
        UserThreadFactory f1 = new UserThreadFactory(" 第 1 机房 ");
        UserThreadFactory f2 = new UserThreadFactory(" 第 2 机房 ");

        UserRejectHandler handler = new UserRejectHandler();

        // 核心线程为1, 最大线程为2, 为了保证触发 rejectHandler
        ThreadPoolExecutor threadPoolFirst = new ThreadPoolExecutor(1, 2,
                60, TimeUnit.SECONDS, blockingDeque, f1, handler);

        // 利用第二个线程工厂实例创建第二个线程池
        ThreadPoolExecutor threadPoolSecond = new ThreadPoolExecutor(1, 2,
                60, TimeUnit.SECONDS, blockingDeque, f2, handler);

        // 创建 400 个任务线程
        Runnable task = new Task();
        for (int i = 0; i < 200; ++i) {
            threadPoolFirst.execute(task);
            threadPoolSecond.execute(task);
        }
      
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值