目 录CONTENT

文章目录

第七章 java中的线程池

FatFish1
2024-10-31 / 1 评论 / 0 点赞 / 51 阅读 / 0 字 / 正在检测是否收录...

ThreadPoolExecutor代码见ThreadPoolExecutor部分

线程池的工作思路

  • 如果当前运行的线程少于corePoolSize,则创建新线程来执行任务(注意,执行这一步骤需要获取全局锁

  • 如果运行的线程等于或多于corePoolSize,则将任务加入BlockingQueue

  • 如果无法将任务加入BlockingQueue(队列已满),则创建新的线程来处理任务(注意,执行这一步骤需要获取全局锁)

  • 如果创建新线程将使当前运行的线程超出maximumPoolSize,任务将被拒绝,并调用RejectedExecutionHandler.rejectedExecution()方法

任务提交思路

execute和submit两个方法:

  • execute()方法用于提交不需要返回值的任务

  • submit()方法用于提交需要返回值的任务。线程池会返回一个future类型的对象,通过这个future对象可以判断任务是否执行成功,并且可以通过future的get()方法来获取返回值,get()方法会阻塞当前线程直到任务完成,而使用get(long timeout,TimeUnit unit)方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完

线程池关闭

shutdown和shutdownNow方法:

它们的原理是遍历线程池中的工作线程,然后逐个调用线程的interrupt方法来中断线程,所以无法响应中断的任务可能永远无法终止(例如下案例)。调用后线程池的isShutdown方法就会返回true

  • shutdownNow首先将线程池的状态设置成STOP,然后尝试停止所有的正在执行或暂停任务的线程

  • shutdown只是将线程池的状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程

public class MyTest {
    public static ExecutorService executor = Executors.newSingleThreadExecutor();
    public static void main(String[] args) throws InterruptedException {
        executor.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                while (true) {
                    if (Thread.currentThread().isInterrupted()) {
                        System.out.println("Interrupted, but running");
                    } else {
                        System.out.println("I'm running");
                    }
                }
            }
        });
        TimeUnit.SECONDS.sleep(3);
        executor.shutdownNow();
        TimeUnit.SECONDS.sleep(10);
    }
}

合理配置线程池资源

  • 对于任务性质分为cpu密集型和IO密集型

    • CPU密集型任务应配置尽可能小的线程,如配置Ncpu+1个线程的线程池。由于IO密集型任务线程并不是一直在执行任务,则配置尽可能多的线程,如2*Ncpu

    • 如果任务能拆分,且cpu部分和io部分耗时差不多,可用拆分成两个任务,能提升吞吐量;如果耗时差的大,则每笔要拆分

  • 对于区分优先级的任务,可使用PriorityBlockingQueue,但是如果高优先级任务一直都在生成,可能出现低优先级任务不执行的风险

  • 依赖数据库连接池的任务,因为线程提交SQL后需要等待数据库返回结果,等待的时间越长,则CPU空闲时间就越长,那么线程数应该设置得越大,这样才能更好地利用CPU

  • 建议使用有界队列,防止因任务阻塞生产者无限提交任务导致爆内存

线程池监控

  • taskCount:线程池需要执行的任务数量。

  • completedTaskCount:线程池在运行过程中已完成的任务数量,小于或等于taskCount。

  • largestPoolSize:线程池里曾经创建过的最大线程数量。通过这个数据可以知道线程池是否曾经满过。如该数值等于线程池的最大大小,则表示线程池曾经满过。

  • getPoolSize:线程池的线程数量。如果线程池不销毁的话,线程池里的线程不会自动销毁,所以这个大小只增不减。

  • getActiveCount:获取活动的线程数。

0

评论区