Java线程池
来源:互联网 发布:适合美工的笔记本 编辑:程序博客网 时间:2024/06/08 06:27
一、原理
1.1 应用场景
1.1.1 为什么要使用线程池?
第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
总体来说,是为了提高系统的整体性能。
1.1.2 使用场景
首先,线程的生命周期及使用时间包括:创建(t1)、 运行(t2)、 销毁(t3),即线程运行的总时间
T = t1 + t2 + t3
假如,有些业务逻辑需要频繁的使用线程执行某些简单的任务,那么很多时间都会浪费t1和t3上(创建和销毁),为了避免不必要的时间开销,可以采用线程池,在线程池中的线程可以复用,当线程运行完任务之后,不被销毁。
1.2 原理实现
结合以下两图,两图中1、2、3、4即是线程池的工作原理,
1、首先线程池判断基本线程池是否已满,如果没满,创建一个工作线程来执行任务。满了,则进入下个流程。
2、其次线程池判断工作队列是否已满,如果没满,则将新提交的任务存储在工作队列里。满了,则进入下个流程。
3、最后线程池判断整个线程池是否已满,如果没满,则创建一个新的工作线程来执行任务。
4、如果整个线程池已经满了,则交给饱和策略来处理这个任务。
二、实现
上述工作原理即是Java线程池的工作原理,同时Java中 java.util.concurrent 包中提供了线程池的实现,即Executor框架,其基本结构图如下图所示:
包括三个部分:
(1)Executor接口
Executor接口是Executor框架中最基础的部分,定义了一个用于执行Runnable的execute方法,它没有实现类只有另一个重要的子接口ExecutorService
public interface Executor { void execute(Runnable command); }
(2)ExecutorService接口
ExecutorService接口继承自Executor接口,定义了终止、提交、执行任务、跟踪任务返回结果等方法
execute(Runnable command):执行Ruannable类型的任务submit(task):可用来提交Callable或Runnable任务,并返回代表此任务的Future对象shutdown():在完成已提交的任务后关闭线程池,不再接管新任务,shutdownNow():停止所有正在执行的任务并关闭线程池。isTerminated():测试是否所有任务都执行完毕了。isShutdown():测试是否该ExecutorService已被关闭
(3)Executors的静态方法
负责生成各种类型的ExecutorService线程池实例,
newFixedThreadPool(numberOfThreads:int):(固定线程池)ExecutorService 创建一个固定线程数量的线程池,并行执行的线程数量不变,线程当前任务完成后,可以被重用执行另一个任务newCachedThreadPool():(可缓存线程池)ExecutorService 创建一个线程池,按需创建新线程,就是有任务时才创建,空闲线程保存60s,当前面创建的线程可用时,则重用它们newSingleThreadExecutor():(单线程执行器)线程池中只有一个线程,依次执行任务newScheduledThreadPool():线程池按时间计划来执行任务,允许用户设定执行任务的时间newSingleThreadScheduledExcutor():线程池中只有一个线程,它按规定时间来执行任务
以下代码是三个例子的实现:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); } public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
上述几个实例都是调用了 ThreadPoolExecutor 类,可根据不同的参数定制不同类型的线程池,
new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, milliseconds,runnableTaskQueue, handler);
其中重要的参数:
private final BlockingQueue<Runnable> workQueue; //任务缓存队列,用来存放等待执行的任务private final ReentrantLock mainLock = new ReentrantLock(); //线程池的主要状态锁,对线程池状态(比如线程池大小 //、runState等)的改变都要使用这个锁private final HashSet<Worker> workers = new HashSet<Worker>(); //用来存放工作集 private volatile long keepAliveTime; //线程存货时间 private volatile boolean allowCoreThreadTimeOut; //是否允许为核心线程设置存活时间private volatile int corePoolSize; //核心池的大小(即线程池中的线程数目大于这个参数时,提交的任务会被放进任务缓存队列)private volatile int maximumPoolSize; //线程池最大能容忍的线程数 private volatile int poolSize; //线程池中当前的线程数private volatile RejectedExecutionHandler handler; //任务拒绝策略private volatile ThreadFactory threadFactory; //线程工厂,用来创建线程private int largestPoolSize; //用来记录线程池中曾经出现过的最大线程数private long completedTaskCount; //用来记录已经执行完毕的任务个数
三、示例
以下是参考示例:设置了一个初始为5,最大容量是10的线程池,开启15个线程开始运行。
public class Test { public static void main(String[] args) { ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(5)); for(int i=0;i<15;i++){ MyTask myTask = new MyTask(i); executor.execute(myTask); System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+ executor.getQueue().size()+",已执行完的任务数目:"+executor.getCompletedTaskCount()); } executor.shutdown(); }} class MyTask implements Runnable { private int taskNum; public MyTask(int num) { this.taskNum = num; } @Override public void run() { System.out.println("正在执行task "+taskNum); try { Thread.currentThread().sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("task "+taskNum+"执行完毕"); }}
- Java线程:线程池
- java--线程--线程池
- Java线程(六):线程池
- Java线程(五):线程池
- Java线程(五):线程池
- Java线程_07_线程池
- Java线程(五):线程池
- Java线程(六):线程池
- Java线程(五):线程池
- Java线程(六):线程池
- Java线程(六):线程池
- Java线程(六):线程池
- Java线程(六):线程池
- Java线程(六):线程池
- Java线程(六):线程池
- Java线程(六):线程池
- Java线程(五):线程池
- Java线程(六):线程池
- Kotlin教程学习-函数定义,变量声明
- Vue-高级讲师之笔记03
- git cherry-pick. 如何把已经提交的commit, 从一个分支放到另一个分支
- Maven详解之仓库------本地仓库、远程仓库
- SQL(2) ---级联联表批量删除
- Java线程池
- Tomcat 部署多个web项目
- OpenGL学习——(3)库函数
- ajaxfileupload同一个文件只能上传一次问题解决
- webcollector爬虫框架使用案例
- mysql 受影响行数,记录ID,存储过程查询
- MyBatis传入参数为list、数组、map写法
- 机器学习20-线性支持向量机svm公式推导(二)
- 20170622的代码