java基础---多线程---JUC线程池
===參考論文
=====使用线程池有哪三个好处呢?
1.重复使用线程,减少线程创建和销毁的消耗。
2.提高响应速度。因为线程已经事先建好了,任务来了可以直接使用,减少响应的时间。
3.提高线程可管理性。线程是稀缺资源不能够无线创建,通过线程池可以高效管理分配。
=====一个任务提交到线程池了后会经过哪些处理步骤呢?
1.先看线程池中的核心线程池。没有满的话新建线程处理任务。
2.再看工作队列。如果工作队列没满,将任务提交到这个队列中。
3.如果队列也满了,但是线程池没满,就创建线程处理任务。
4.如果整个线程满了,就执行拒绝策略处理来的请求。
=====创建一个线程池的时候可以指定哪些参数呢?阻塞队列有哪些以及具体应用?拒绝策略有哪些呢?
1.核心线程数量
2.最大线程数量
3.线程空闲存活时间
4.阻塞队列
5.拒绝策略
6.线程创建工厂Factory
---阻塞队列包括:
数组阻塞队列(固定大小先进先出)
链表阻塞队列(基于链表,先进先出,newFixedThreadPool就是用这个实现的)
同步阻塞队列(不存储元素,每次插入必须有另一个线程做移除,吞吐量高,newCachedThreadPool)
优先级阻塞队列(具有优先级的无线阻塞队列)。
-----拒绝策略:抛异常,直接放弃任务,删除掉队列中最老的记录,然后执行当前任务,或者使用提交任务的线程执行任务。
===向线程池提交任务的方式有几种呢?
分别是execute()和submit(),execute不返回结果,所以执行runnable接口;submit有返回值,能够返回future对象。
execute没有返回值,不知道任务是否执行成功
submit返回一个future对象,通过get方法可以通过阻塞的去获取任务的执行结果
ExecutorService pool = Executors.newFixedThreadPool();
pool.execute(new Runnable(){});
Future future = pool.submit(Callable);
===什么是future模式
如果一个很耗时的任务需要执行,而且这个返回值不是立刻需要的时候,就可以使用FutureTask去重新启动一个线程去执行,然后使用Future.get()来获取结果,这就是Future模式。
//使用FutureTask去承载一个Callable要执行的任务
FutureTask<Integer> futureTask = new FutureTask<Integer>(callable);
//使用线程去执行,因为FutureTask实现了Runnable所以可以放到一个线程中执行。
new Thread(futureTask).start();
//最后异步地去获取结果
System.out.println(futureTask.get());
===对于cpu密集型任务和io密集型任务分别如何设置线程池线程大小呢?
cpu密集,就是需要长时间的计算处理,线程数量可以少一些。
io密集,那么线程等待结果的时间会比较长,cpu空闲时间就长,所以线程数量可以相对多一些。
===有界队列和无界队列要选择哪种比较好呢?
尽量使用有界队列。有界队列可以实现系统的稳定性,但是可以尽量设置大一点,几千。
如果设置成无界队列,那么线程池的队列就会越来越多,内存会溢出,导致整个系统 崩溃,会波及到其他的任务。
=====java中本身提供的线程池具体实现有哪两大类呢?有什么区别呢?
具体有ThreadPoolExecutor和ScheduledThreadPoolExecutor
1.区别就是后者使用了延迟队列DelayedQueue延迟队列,加入了一定的延迟和定时效果。
=====ThreadPoolExecutor有哪三种具体的实现呢?
第一种:FixedThreadPool可重用固定线程池线程固定,使用链表阻塞队列,所以阻塞的任务可以无限制的插入到队列中,也就是说线程最大值,线程存活时间,线程拒绝策略这些参数都是没有用的。适用于资源有限制,线程数量有限制的负载比较重的场景。
第二种:SingleThreadExecutor单一线程,核心线程数和最大线程数都是1,使用链表阻塞队列,只有一个线程处理任务,适用于顺序处理任务的情况
第三种:CachedThreadPool,线程无数会根据需要创建线程的线程池。核心数为0,最大值无穷大,可以根据任务实际情况来创建和销毁线程。线程空闲时间60s,使用没有容量的同步队列来作为阻塞队列,这种阻塞队列必须先执行掉一个任务才能够插入一个任务。一个任务提交进来,如果有空闲的线程,那么就直接执行任务,如果没有空闲的就创建新的线程去执行。适用于执行很多短期异步任务的情况,负载教轻的场景。
=====ScheduledThreadPoolExecutor介绍?
底层使用延迟队列DelayedQueue来保存任务,延迟队列通过优先队列来具体的保存任务的。一个任务提交进来会进行ScheduleFutureTask的封装,任务有编号,执行的时间,执行的周期三个参数。
具体的执行过程:线程会获取到时的任务并且执行,然后修改任务下次执行时间重新插入到队列中。
===线程池的生命周期和线程池状态,简述线程池的五种状态?
使用AtomicInteger的参数来记录线程池的状态ctl
ctl共包括32位。其中,高3位表示"线程池状态",低29位表示"线程池中的任务数量"。
running---接受新任务,处理旧任务,处理中的继续处理
shutdown---不接受新任务,处理旧任务,处理中的继续处理
stop---不接受新任务,不处理旧任务,处理中的中断
tidying---整理状态,就是当任务数量为0,队列为空的时候,从shutdown状态进入到整理状态。
terminated---终止状态,从tidying执行terminate()方法之后进入的状态。