java线程池详解
来源:互联网 发布:网络编辑部简介 编辑:程序博客网 时间:2024/05/18 18:17
一,线程池是指管理一组同构工作线程的资源池,包含两部分:work queue and work thread,工作队列保存所有等待执行的任务,工作线程的任务很简单:从工作队列中获取任务,执行任务,然后返回线程池并等待下一个任务。
二 ,线程池的管理:
1,ThreadPoolExecutor->AbstractExecutorService->ExecutorService->Executor
ThreadPoolExecutor构造函数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {}
只有等工作队列满了之后,才会创建大于基本大小的线程。
2, 设置线程池的大小:
Ncpu= number of CPUs
Ucpu=target CPU utilization , 0<=Ucpu<=1
W/C= ratio of wait time to compute time
要使处理器达到期望的使用率,线程池的最优大小为:
Nthreads=Ncpu * Ucpu * (1+W/C)
可以通过Runtime来获取CPU的数目:
int N_CPU=Runtime.getRuntime().availableProcessors();
对于计算密集型任务,线程池大小一般设置为N_CPU+1;
对于包含I/O 操作或者其他阻塞操作的任务,由于线程并不会一直运行,因此线程池的规模应该更大。
要正确的设置线程池大小,必须估算出等待时间和计算时间的比值。
3,饱和策略:
AbortPolicy: 中止策略,默认的饱和策略,抛出未检查的RejectedExecutionException.
DiscardPolicy: 抛弃策略会悄悄抛弃该任务。
DiscardOldestPolicy: 抛弃下一个将被执行的任务,然后尝试重新提交任务。
CallerRunsPolicy: 调用者运行,当线程池中的所有线程都占用,并且工作队列被填满之后,下一个任务将在调用execute时
在主线程中执行,由于执行需要一定的时间,因此主线程至少一段时间内不能提交任何任务,从而使得工
作线程有时间来处理正在执行的任务,在这期间,主线程不会调用accept,因此到底的请求将保存在TCP
层的队列中而不是应用程序的队列中,如果持续过载,那么TCP层将最终发现它的请求队列被填满,因此
开始抛弃请求。从线程池到工作队列到应用程序再到TCP层,最终到达客户端,导致服务器在高负载下实
现一种平缓的性能降低。
4,生命周期:
JVM只有在所有(非守护)线程全部终止后才会退出,因此如果无法正确的关闭Executor,那么JVM将无法结束。
shutdown(): 执行平缓的关闭过程,不再接受新的任务,同时等待已经提交的任务执行完成——包括那些还未开始的任务。
shutdownNow(): 执行比较粗暴的关闭过程,它将尝试取消所有正在运行的任务,并且不再启动队列中尚未开始的任务。
其实调用的都是thread.interrupt();
一般这样关闭:
exec.shutdown();
exec.awaitTermination(long timeout, TimeUnit unit);
三,Executors类提供了四种基本的线程池构造方式
a, Executors.newFixedThreadPool(int nThreads)
线程数量nThreads是固定的,使用一个无界的LinkedBlockingQueue。
b, Executors.newSingleThreadExecutor()
作用等同于Executors.newFixedThreadPool(1),但是唯一区别就是它返回的是一个保证不会被额外线程重构的一个Executor
c, Executors .newCachedThreadPool() 等同于
new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
These pools will typically improve the performance of programs
that execute many short-lived asynchronous tasks.
SynchronousQueue不是一个真正的队列,只是一种线程之间作为信息移交的一种机制,要将一个元素放入SynchronousQueue,必须有另一个线程正在等待接受这个元素,如果没有线程正在等待,
并且线程池的当前大小小于最大值,那么将创建一个新的线程,否则根据饱和策略,这个任务将被拒绝。
d, Executors .newScheduledThreadPool(int corePoolSize)
Creates a thread pool that can schedule commands to run after a
given delay, or to execute periodically。
默认为一个无界的DelayedWorkQueue()
四,注意点:
1,线程池初始化完了之后,实际线程数为0,只有当有任务执行时,才会创建线程,根据执行任务数的增多,线程池中的线程数逐步达到coreSize,然后处于稳定状态,当线程池中的线程都处于繁忙状态时,后续任务会进入等待队列中,线程会从队列中获取任务来执行,当队列被填满时,就会创建新的线程,直到到达maxSize, 如果还是不行,就会执行饱和策略。
2,线程池默认创建的为非守护线程,也就意味着即使发生异常,JVM也无法自动退出,必须关闭线程池或者调用System.exit()强制退出。意味着线程池是无法被GC掉的,只有调用了shutdown()之后,才会被GC。
3,如果一个线程池没有被程序再引用,并且没有剩余的线程,那么它会自动shutdown. 如果你想确保没有被引用的线程池一定会被回收,即使用户忘记调用shutdown(),那么你可以通过设置keep-alive times来安排空闲的线程最终死亡,coreSize设置为0或者设置ThreadPoolExecutor#allowCoreThreadTimeOut(true)
4,子类线程池可以定制化,执行前设置ThreadLocal,或者记录log等等。
protected void beforeExecute(Thread t, Runnable r) { }
protected void afterExecute(Runnable r, Throwable t) { }
- java 线程池详解
- java线程池详解
- java 线程池 详解
- Java线程池详解
- JAVA线程池详解
- java线程池详解
- java线程池详解
- java 线程池详解
- java线程池详解
- Java线程池详解
- Java 线程池详解
- JAVA 线程池详解
- java线程池详解
- Java线程池详解
- JAVA线程池详解
- java 线程池详解
- Java线程池详解
- java 线程池详解
- Android中的onWindowFocusChanged()方法详解
- php redis 安装扩展
- 基于Python的网络爬虫入门
- 数据挖掘
- codeforces665b 模拟
- java线程池详解
- 一个android工程代码多个差异化项目管理方法探讨
- 202. Happy Number
- ARM
- php代码优化
- 决策树C4.5
- 从ScrollView嵌套EditText的滑动事件冲突分析触摸事件的分发机制以及TextView的简要实现和冲突的解决办法
- nfl_suspensions
- 三级数据库知识点