线程池讲解第二回

本文详细解析了Java线程池的核心类ThreadPoolExecutor,包括其工作原理、关键方法如execute(), addWorker(), runWorker()和getTask(),以及常用的Executor和ExecutorService接口。还介绍了线程池的创建工具Executors和不同策略,如固定线程池、缓存线程池等,以及如何监控和避免OOM问题。
摘要由CSDN通过智能技术生成
Java线程池的构造
Java线程池的类关系图

Java线程池类关系图

线程池的核心类 ThreadPoolExecutor

ThreadPoolExecutor: 所有的其他类和接口,都是围绕这个类提供的各自功能。

  1. AtomicInteger ctl:记录线程池状态和线程池数量,选择32位来记录,高3位用来记录线程状态,低29位记录线程数量。111:running,000:shutdown,001:stop,010:tidying,011:terminated。

  2. execute()方法:执行任务的方法。

    主要是通过判断线程数量,来执行addWorker()方法。

    判断线程池状态,增加到队列成功之后,再判断一次状态和移除任务成功之后执行reject()方法。如果线程池的数量为0的时候,执行addWorker()方法。

    判断线程池状态,增加到队列失败之后,在判断addWorker()是否成功,如果返回false执行reject()方法。

  3. addWorker()方法:将任务增加队列。

    这个方法,先判断一些线程池的状态,然后再判断线程池数量,然后再对ctl加1。

    接着执行new Worker()操作,然后加锁之后,判断线程池状态,增加到workers中,释放锁之后,启动线程,t.start(),Worker内部类中run()中调用了,runWorker()方法。

  4. runWorker()方法,这里执行增加锁,增加状态的判断,一些前置操作,和一些后置操作。再通过判断getTask()操作,获取在队列中的任务,来执行。所以runWorker方法,就是执行当前任务,执行完了,再去获取队列中的任务执行。

  5. getTask()方法,判断状态,判断是否需要判断超时,如果需要超时判断则执行workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS),不需要超时判断就执行workQueue.take()。

**总结:**这个就是ThreadPoolExecutor的执行的大概流程。与上一回自己手写的流程大概过程是一样的,但是Java的执行过程增加状态判断,锁操作,队列操作考虑的更加完善。

接口Executor,ExecutorService

接口Executor定义线程池的执行方法:

void execute(Runnable command)

接口ExecutorService定义了线程池方法:

void shutdown();
List<Runnable> shutdownNow();
boolean isShutdown();
boolean isTerminated();
<T> Future<T> submit(Callable<T> task);
抽象类AbstractExecutorService

主要是实现了一些基本通用的方法

内部类Worker

这个类就是任务执行了类,通过run()调用runWorker()方法来执行自身当前的任务,也可以取出线程池队列中的任务进行执行。

RejectExecutionHandler:拒绝策略接口

AbortPlicy:抛出异常方式拒绝

DiscardPolicy:直接丢弃

DiscardOldPolicy: 丢弃存活时间最长的任务

CallerRunsPolicy:谁提交谁执行

如果自定义拒绝策略则通过实现这个接口

Executors: 创建我们常用不同策略的线程池

算是一个线程池创建的工具类,创建4中不同功能的线程池。

newFixedThreadPool:固定大小的线程池,LinkedBlockingQueue的无界阻塞队列存放等待线程,任务不能及时处理,无限的堆积,可能导致OOM。

newCachedThreadPool: 没有现在数量,最大数量设置为Integer.MAX_VALUE,SynchronousQueue 是一个生产消费模式的阻塞队列,只要有任务就需要线程执行,如果线程任务比较耗时,又需要大量创建,会导致OOM。

newScheduledThreadPool: 创建一个可以指定时间周期的线程池,new ScheduledThreadPoolExecutor.DelayedWorkQueue(),这个也是无限大小的线程池Integer.MAX_VALUE。这个也是无界阻塞队列存放线程,也存在OOM的异常。

newSingleThreadExecutor:只有一个线程的线程池;LinkedBlockingQueue的无界阻塞队列存放等待线程

这些线程池都有可能出现OOM的异常。

三, 线程池的使用

​ 为什么要是用线程池,因为使用了多线程,但是单独new Thread(),肯定会造成资源的浪费,通过线程池减少这种浪费。多线程是用来提高服务器并发处理能力,减少服务器平均处理时间,减少服务端的压力,缩短服务处理的时间。

​ 涉及到了理论的知识,利特尔法则阿姆达尔定律;利特尔法则就是增加服务,或是缩短周期。所以在实际的工作中通过,我可以将服务修改为并行处理。这样就缩短的服务返回的时间。

​ Executors这个类是Java提供的,但是这个类创建的线程不够精细化,也非常容易造成OOM风险,所以实际的工作中,可以通过new ThreadPoolExecutor(),也可以使用Spring的线程配置ThreadPoolTaskExecutor。new ThreadPoolExecutor

获取线程池监控信息
  1. 通过重写线程池方式来监控
public classs ThreadPoolMonitor extends ThreadPoolExecutor {
    @Override
    public void shutdown {
        ...
    }
    ...
}
  1. 基于JVMTI方式来监控

JVMTI就是JVM tool interface.通过c++代码来实现JVM层面的性能分析,内存管理,线程分析等。

总结

当业务量很小的时候,不需要复杂的技术;但是大厂他们的业务体量庞大,并发数高,让原本可能就是一个简单的查询接口,需要做熔断降级限流缓存线程异步预热等等的操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值