My Life My Dream!

守信 求实 好学 力行
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Java线程池的使用示例及注意事项

Posted on 2022-03-12 18:44  召冠  阅读(543)  评论(0编辑  收藏  举报

创建线程的代价是昂贵的,还会给GC带来压力,如果频繁创建线程那么GC的时候也需要回收对应的线程资源。使用线程池,一方面可以提升线程的使用率,减少对象的创建、销毁;另外,线程池还可以有效控制线程数,提升服务器的使用资源,避免因线程使用不当导致资源不足而发生宕机等问题。

示例代码如下:

 

     public static final String THREAD_NAME_PREFIX = "listen-async-send-thread-";
     private static final ThreadPoolExecutor executor =
             new ThreadPoolExecutor(4, 32, 10, TimeUnit.MINUTES,
                     new LinkedBlockingQueue<Runnable>(10000),
                     new ThreadFactory() {
                         private AtomicInteger id = new AtomicInteger(0);

                         @Override
                         public Thread newThread(Runnable r) {
                             Thread thread = new Thread(r);
                             thread.setName(THREAD_NAME_PREFIX + id.addAndGet(1));
                             return thread;
                         }
                     }, new ThreadPoolExecutor.CallerRunsPolicy());


     public void listen(HibernateChangeEntity changeEntity) {
        
         executor.execute(new Runnable() {
             @Override
             public void run() {
                 try {
                     if (Thread.currentThread().getName().startsWith(THREAD_NAME_PREFIX)) {
                         // 构造线程上下文

                     }

                    // 业务代码部分

                } catch (Throwable e) {

                } finally {
                     if (Thread.currentThread().getName().startsWith(THREAD_NAME_PREFIX)) {
                         // 清理线程上下文的信息

                     }
                 }
             }
         });
    }

 

 

建议及注意事项:

1、设定线程名的统一前缀,便于跟踪查看及问题排查

2、合适的初始线程数、最大线程数及任务队列容量(只有超过队列容量,池才会在coreSize基础上创建新的线程)

3、设置及清理线程上下文等信息(因为线程会被复用,如果不进行清理,会影响后续业务逻辑和造成内存泄露等问题)

4、捕捉所有异常并做按需处理

5、ThreadPoolExecutor执行顺序

  1. 当线程数小于核心线程数时,创建线程。
  2. 当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。
  3. 当线程数大于等于核心线程数,且任务队列已满
    1. 若线程数小于最大线程数,创建线程
    2. 若线程数等于最大线程数,拒绝任务,触发rejectedExecutionHandler对应的策略

6、线程池会调用rejectedExecutionHandler来处理这个任务。如果没有设置默认是AbortPolicy,会抛出异常

ThreadPoolExecutor类有几个内部实现类来处理这类情况:
1、AbortPolicy 丢弃任务,抛运行时异常
2、CallerRunsPolicy 回到主线程执行任务
3、DiscardPolicy 忽视,什么都不会发生
4、DiscardOldestPolicy 从队列中踢出最先进入队列(最后一个执行)的任务

另外,就是实现RejectedExecutionHandler接口,可自定义处理器

 

参考资料:

https://blog.csdn.net/qq_23000805/article/details/89208561