一图看懂线程池执行一个工作单元(Runnable,callable)过程

从JDK 5开始,把工作单元执行机制分离开来,工作单元包括Runnable和Callable,而执行机制有Executor框架提供
全文参考

线程池四大组件

1.线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
2、工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
4、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。

为什么会出现线程池这种池化技术

假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间
:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。
线程池会把T1安排在程序启动的时候,T3会安排在程序结束的时候,这样子就会在服务器处理请求的时候不会有T1和T3的开销,同时加入了任务队列,只要任务队列不为空,线程池中的线程就会不断地从任务队列那里拿出任务来执行,除非任务队列中的任务为空(这种情况很少的),不断的取任务保持了线程不会终止,不会说处理完了一个任务这个线程就被销毁。

优势:
1)降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

(2)提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。

(3)提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

线程池的执行计划类关系图
在这里插入图片描述

java四种常见的线程池(子类)

定长线程池(FixedThreadPool)
定时线程池(ScheduledThreadPool )
可缓存线程池(CachedThreadPool)
单线程化线程池(SingleThreadExecutor)
在这里插入图片描述

一图看懂线程池新增一个任务流程

在这里插入图片描述
个人理解:main函数主线程(或者其他接受请求封装请求的线程)要求处理一个任务,这个时候执行executor,提交一个任务,封装类底层可能会把这个Runnable对象或者callbale对象放入任务队列中。首先会判断是不是核心线程数量是不是达到上限,如果没有就新建一个核心线程来执行这个任务,并且把这个新的线程放入线程池,这个新的线程会从任务队列中取出任务继续执行。

如果核心线程达到了上限,如果任务队列(一个Runnable或者callable的list集合)没有达到上限,就会把这个任务add入这个队列尾部(注意:这个任务不会立即执行,要等前面的任务执行完了才轮到自己);如果任务队列满了,这个时候不会放入队列里面,会进入下一个判断(是不是非核心线程达到数量)。

如果任务队列满了,且非核心线程没达到上限,就会新建一个线程来执行这个任务(这个也是立即执行的);如果非核心线程也达到上限,就会拒绝处理这个任务。执行拒绝策略。结束。

最后是最重要的取任务的时间设置:如果任务队列里面的任务是空的,不可能这么多线程一直活着的,这样子会很浪费资源的。一般设置好了取任务时间,如果不能在规定时间取到任务就会回收线程(摧毁线程)。如果没设置时间会一直阻塞活着。

如何做到任务为空,线程活着一段时间,if判断list是不是空,是的话就while循环一个时间,过了就死亡。。。

线程池的七大参数

**1.corePoolSize:**核心线程池数量
**2.maximumPoolSize 😗*最大线程池线程数量
3.keepAliveTime 空闲线程存活时间,一个线程如果处于空闲状态,并且当前的线程数量大于corePoolSize,那么在指定时间后,这个空闲线程会被销毁,这里的指定时间由keepAliveTime来设定

4.unit 空间线程存活时间单位

keepAliveTime的计量单位,和keepAliveTime作比较,大于等于这个时间就销毁

5.workQueue 工作队列

新任务被提交后,会先进入到此工作队列中,任务调度时再从队列中取出任务,JDk提供了4种工作队列

6threadFactory 线程工厂

创建一个新线程时使用的工厂,可以用来设定线程名、是否为daemon线程等等

7.handle 拒绝策略当工作队列中的任务已到达最大限制,并且线程池中的线程数量也达到最大限制,这时如果有新任务提交进来,该如何处理呢。这里的拒绝策略,就是解决这个问题的,jdk提供的拒绝策略有四种

*线程池的使用ThreadPoolExecutor实例

指定上面7个参数

public class ThreadPool {
    private static ExecutorService pool;
    public static void main( String[] args )
    {
        //自定义线程工厂
        pool = new ThreadPoolExecutor(2, 4, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(5),
                new ThreadFactory() {
            public Thread newThread(Runnable r) {
                System.out.println("线程"+r.hashCode()+"创建");
                //线程命名
                Thread th = new Thread(r,"threadPool"+r.hashCode());
                return th;
            }
        }, new ThreadPoolExecutor.CallerRunsPolicy());
          
        for(int i=0;i<10;i++) {
            pool.execute(new ThreadTask());
        }    
    }
}

public class ThreadTask implements Runnable{    
    public void run() {
        //输出执行线程的名称
        System.out.println("ThreadName:"+Thread.currentThread().getName());
    }
}

四大拒绝策略


当线程池的线程数达到最大线程数时,需要执行拒绝策略。拒绝策略需要实现RejectedExecutionHandler接口,并实现rejectedExecution(Runnable r, ThreadPoolExecutor executor)方法。不过Executors框架已经为我们实现了4种拒绝策略:

AbortPolicy(默认):丢弃任务并抛出RejectedExecutionException异常。
CallerRunsPolicy:由调用线程处理该任务。
DiscardPolicy:丢弃任务,但是不抛出异常。可以配合这种模式进行自定义的处理方式。
DiscardOldestPolicy:丢弃队列最早的未处理任务,然后重新尝试执行任务。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值