⾼并发⾯试:线程池的七⼤参数?⼿写⼀个线程池?线程池
1. Callable接⼝的使⽤
package;
import Callable;
import ExecutionException;
import FutureTask;
/**
* 多线程中,第三种获得多线程的⽅式
* */
带来不便public class CallableTest {
public static void main(String[] args)throws ExecutionException, InterruptedException {
/
/FutureTask(Callable<V> callable)
FutureTask<Integer> futureTask =new FutureTask<>(new myThread());
new Thread(futureTask,"AAA").start();
//new Thread(futureTask, "BBB").start();//复⽤,直接取值,不要重启两个线程
int a =100;
int b =0;
//b = ();//要求获得Callable线程的计算结果,如果没有计算完成就要去强求,会导致堵塞,直到计算完成
while(!futureTask.isDone()){
当futureTask完成后取值
b = ();
}
System.out.println("===Result is:"+(a + b));
}
}
class myThread implements Callable<Integer>{
acca考试费用@Override
public Integer call()throws Exception {
System.out.println(Thread.currentThread().getName()+"\tget in the callable");
Thread.sleep(5000);
kuyureturn1024;
}
}
两者区别:
Callable:有返回值,抛异常
Runnable:⽆返回值,不抛出异常
2. 为什么要使⽤线程池
1. 线程池做的⼯作主要是控制运⾏的线程的数量,处理过程中将任务放⼊队列,然后在线程创建后启动给这些任务,如果线程数量超过
了最⼤数量,超出数量的线程排队等候,等其他线程执⾏完毕,再从队列中取出任务来执⾏
2. 主要特点
线程复⽤、控制最⼤并发数、管理线程
1. 减少创建和销毁线程上所花的时间以及系统资源的开销 => 减少内存开销,创建线程占⽤内存,创建线程需要时间,会延迟处理
的请求;降低资源消耗,通过重复利⽤已创建的线程降低线程创建和销毁造成的消耗
2. 提⾼响应速度。当任务到达时,任务可以不需要等到线程创建就能⽴即执⾏
2015上海中考分数线
3. 提⾼线程的客观理性。线程是稀缺资源,如果⽆限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使⽤线程池可以进
⾏统⼀的分配,调优和监控(根据系统承受能⼒,达到运⾏的最佳效果) => 避免⽆限创建线程引起的OutOfMemoryError【简称OOM】
3. 线程池如何使⽤?
1. 架构说明
Java中的线程池是通过Executor框架实现的,该框架中⽤到了 :Executor,Executors,ExecutorService,ThreadPoolExecutor
2. 编码实现
实现有五种,wScheduledThreadPool()是带时间调度的,java8新推出
重点有三种
1. wFixedThreadPool(int)
执⾏长期的任务,性能好很多
expiry
创建⼀个定长线程池,可控制线程最⼤并发数,超出的线程回在队列中等待newFixedThreadPool创建的线程池corePoolSize 和maximumPoolSize值是相等的,它使⽤的是 LinkedBlockingQueue
为难英文底层源码:
底层源码:
2. wSingleThreadExecutor()
⼀个任务⼀个任务执⾏的场景
沈阳体育学院学报创建⼀个单线程话的线程池,他只会⽤唯⼀的⼯作线程来执⾏任务,保证所有任务按照指定顺序执⾏
newSingleThreadExecutor将corePoolSize和maximumPoolSize都设置为1,使⽤LinkedBlockingQueue
源码:
3. wCachedThreadPool()
执⾏很多短期异步的⼩程序或负载较轻的服务器
创建⼀个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲县城,若⽆可回收,则新建线程英语学习视频网站
newCachedThreadPool将corePoolSize设置为0,将maximumPoolSize设置为Integer.MAX_VALUE,使⽤ 的SynchronousQueue,也就是说来了任务就创建线程运⾏,当县城空闲超过60s,就销毁线程
源码:
我们可以看到底层的代码都是由ThreadPoolExecutor这个类的构造⽅法创建的,只是传⼊的参数不同,那么研究⼀下这个类以及这些参数就很有必要,下节我们将介绍这些参数的使⽤
pennsylvania3. ThreadPoolExecutor
4. 线程池的⼏个重要参数
核⼼执⾏代码为:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue){
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
那么我们再点进this⽅法可以看到其全参数的构造⽅法为:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
简单介绍⼀下:
1. corePoolSize: 线程池中常驻核⼼线程数
1. 在创建了线程池后,当有请求任务来之后,就会安排池中的线程去执⾏请求任务
2. 当线程池的线程数达到corePoolSize后,就会把到达的任务放到缓存队列当中
2. maximumPoolSize: 线程池能够容纳同时执⾏的最⼤线程数,必须⼤于等于1
3. keepAliveTime: 多余的空闲线程的存活时间
1. 当前线程池数量超过corePoolSize时,档⼝空闲时间达到keepAliveTime值时,多余空闲线程会被销毁到只剩下corePoolSize
个线程为⽌
4. unit: keepAliveTime的单位
5. workQueue: 任务队列,被提交但尚未被执⾏的任务
任务队列底层是BlockingQueue阻塞队列!不清楚阻塞队列的参考这篇⽂章:
6. ==threadFactory:==表⽰⽣成线程池中⼯作线程的线程⼯⼚,⽤于创建线程⼀般⽤默认的即可
7. handler: 拒绝策略,表⽰当队列满了并且⼯作线程⼤于等于线程池的最⼤线程数(maximumPoolSize)时如 何来拒绝请求执⾏的
runable的策略
5. 线程池的底层⼯作原理以及过程
如上图所属,其流程为:
1. 在创建了线程池之后,等待提交过来的任务请求
2. 当调⽤execute()⽅法添加⼀个请求任务时,线程池会做出如下判断:
2.1 如果正在运⾏的线程数量⼩于corePoolSize,那么马上创建线程运⾏这个任务;
2.2 如果正在运⾏的线程数量⼤于或等于corePoolSize,那么将这个任务放⼊队列;
2.3 如果此时队列满了且运⾏的线程数⼩于maximumPoolSize,那么还是要创建⾮核⼼线程⽴刻运⾏此任务;
2.4 如果队列满了且正在运⾏的线程数量⼤于或等于maxmumPoolSize,那么启动饱和拒绝策略来执⾏
3. 当⼀个线程完成任务时,他会从队列中取出下⼀个任务来执⾏
4. 当⼀个线程⽆事可做超过⼀定的时间(keepAliveTime)时,线程池会判断:
如果当前运⾏的线程数⼤于corePoolSize,那么这个线程会被停掉;所以线程池的所有任务完成后他
tradeoff
最⼤会收 缩到corePoolSize的⼤⼩
5. 实际⼯作中如何设置合理参数
5.1 线程池的拒绝策略
1. 什么是线程的拒绝策略
1. 等待队列也已经排满了,再也塞不下新任务了,同时线程池中的max线程也达到了,⽆法继续为新任务服务。这时我们就需要拒
绝策略机制合理的处理这个问题
2. JDK内置的拒绝策略
1. AbortPolicy(默认):如果满了会直接抛出RejectedExecutionException异常阻⽌系统正常运⾏
2. CallerRunsPolicy:”调⽤者运⾏“⼀种调节机制,该策略既不会抛弃任务,也不会抛出异常,⽽是将某些任务回退到调⽤
者, 从⽽降低新任务的流量
3. DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加⼊队列中尝试再次提交当前任务
4. DiscardPolicy:直接丢弃任务,不予任何处理也不抛异常。如果允许任务丢失,这是最好的⼀种⽅案
3. 均实现了RejectedExecutionHandler接⼝