线程池实现原理
--------------------------------------------------------------------------------------------------------------
线程池是一个能够接受任务提交并将任务交给线程执行的类。
它的功能包括对任务的管理和对线程的管理。
它主要通过以下方式来实现这两个功能:
定义属性:
corePoolSize, maxPoolSize, keepAliveTime, blockingQueue,
threadFactory, rejectedExecutionHandler,
runState[RUNNING, SHUTDOWN, STOP, TIDYING, TERMINATED],
workers: Worker是一个封装了thread和task的类.
实现方法:Executor.execute(Runnable task)
任务的管理:
当采用execute()提交任务时,判断worker的数量是否达到了corePoolSize:
如果worker的数量小于corePoolSize:
直接创建新的线程,并将task交给新建的线程去执行;
如果worker的数量大于或等于corePoolSize:
如果blockingQueue未满:
尝试将task放入blockingQueue的末尾;
如果blockingQueue已满:
尝试创建新的线程:
如果创建线程成功:
将任务交给线程去执行
如果创建线程失败:
根据拒绝执行策略处理任务(
AbortPolicy:default policy, 抛出拒绝执行异常;
DiscardPolicy: 悄咪咪地抛弃任务;
DiscardOldestPolicy: 移除队列头的任务,然后再次尝试将这个新任务加入队尾;
CallerRunsPolicy:把任务丢回给调用者,让调用者自己去执行;)
线程管理:[任务干完之后,coreThreadPool的线程在干嘛?Idle是一个什么样的状态呢?]
线程池初始化的时候不会创建线程,默认只有任务到达时才创建线程。除非调用了prestartAllCoreThreads() 去创建核心线程。
线程每次执行完任务后会到blockingQueue中获取任务,若拿到任务则继续执行。
若(任务队列已经为空 或 线程池状态不为RUNNING) 并且 (当前池中线程数量大于 corePoolSize 或 allowCoreThreadTimeOut = true),则尝试interrupt当前线程。否则尝试从任务队列中获取任务,此时调用的是blockingQueue.take()方法,当queue为空时,take方法会调用notEmpty.await()挂起当前线程,并将当前线程加入任务队列的takeLock:ReentrantLock的notEmpty :Condition的等待队列, 等待有新的任务进入时被唤醒。当有新的任务进入队列时(比如ArrayBlockingQueue.enqueue(e)), 会调用notEmpty.signal()去唤醒一个等待的线程。
线程池就是通过这种方式实现线程重用的。
--------------------------------------------------------------------------------------------------------------