线程池的有点
1.降低资源的消耗:系统每创建一个线程都是资源消耗的,如果业务并发量很大,而且每个任务处理速度快,频繁创建线程会引起系统性能下降,避免由于线程创建数量巨大,引起系统资源不足导致内存溢出。
2.提高响应速度:当有新任务来的时候,不需要创建线程,而直接使用线程池中的线程。
线程池的使用
Executor:是一个接口,只有一个方法execute,ExecutorService接口继承了Executor,并且提供了其他一些线程池方法。AbstractExecutorService是ExecutorService默认实现类,提供了部分方法的默认实现,ThreadPoolExceutor就是线程池的实现类,他继承了AbstractExecutorService类,对其进行了扩展,但是在使用的java线程池的时候,通常不直接使用ThreadPoolExceutor去创建java线程池。通常使用Executors工厂类,创建不同的线程池对象,一般有4种:
1.固定大小线程池 2带缓冲功能的线程池对象 3只有一个线程的线程池对象 4执行定时任务的线程池
期中前三个方法都是都通过 new ThreadPoolExceutor,创建对象的时候,传入不同的参数来实现的。
ThreadPoolExceutor的构造方法一般有以下几个参数:
corePoolSize:线程池的核心线程数,当一个任务被添加到线程池的时候,判断线程池中的线程数是不是等于corePoolSize,如果等于,那么新来的任务会放入到阻塞队列中,等待被执行。
maximumPoolSize:当线程池中的阻塞队列已经满了,又有新任务添加到线程池中的时候,如果当前线程池中的线程数,小于maximumPoolSize,那么线程池会创建新的线程去执行任务。
keepAliveTime:当前线程没有执行任务,继续存活的时候,如果当前线程池中的数目大corePoolSize,多出的线程会被停掉
workQueue:阻塞队列的实现方法
handler:线程池的饱和策略
ThreadPoolExceutor执行线程任务分为两种方式:exceute和sumbit,分别调用这两个方法:
submit的方法中把 callable对象或者runable对象包装成一个FutureTask的对象:
RunnableFuture<T> ftask = newTaskFor(task);
1.判断当前线程池线程数量小于corePoolSize,创建新线程。
2.如果数量大于等于coresize,线程池属于运行状态且加入阻塞队列,如果成功执行3,否则执行4
3.重新检查线程池运行状态,如果线程池没有RUNNING,且成功从阻塞队列中删除任务,则执行reject方法处理任务;
4.如果线程池不是RUNNING状态或者加入阻塞队列失败,则尝试创建新线程直到maxPoolSize,如果失败,则调用reject()方法运行相应的拒绝策略。
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
//第一步
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
//第二步
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
//第三步
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
//第四步
else if (!addWorker(command, false))
reject(command);
}
addWorker方法是完成创建线程池线程的功能,下面介绍一下addWorker的实现:
boolean addWorker(Runnable firstTask, boolean core)
addWorker两个参数,第一个表示任务,第二个表示是启动core核心线程还是maximumPoolSize线程。
addWorker主要是将来的线程任务firstTask包装成一个Work对象:w,work是一个runnable接口的实现,然后通过w对象获取当前线程t,然后启动t线程,t线程就是w对象自己的线程。
t线程执行的内容是:
runWorker(this)方法:该this代表w对象自己,runWorker方法内就是执行firstTask的任务:
入上图所示:task.run()方法会执行上面中的ftask对象的run方法:
由于ftask对象是FutureTask类的对象,因此task.run(),调用的是就是FutureTask的run方法:
因为这里run方法会执行call方法,在执行call可以保持返回值和获取异常信息,因此在get的时候,就能获取到方法的返回值和捕捉到异常信息。
网友评论