什么是线程池数据库
线程池是一种多线程处理形式,处理过程当中将任务添加到队列,而后在建立线程后自动启动这些任务。线程池线程都是后台线程。每一个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。若是某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另外一个辅助线程来使全部处理器保持繁忙。若是全部线程池线程都始终保持繁忙,但队列中包含挂起的工做,则线程池将在一段时间后建立另外一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程能够排队,但他们要等到其余线程完成后才启动。缓存
为何使用线程池安全
使用线程池最大的缘由就是能够根据系统的需求和硬件环境灵活的控制线程的数量,且能够对全部线程进行统一的管理和控制,从而提升系统的运行效率,下降系统运行运行压力;固然了,使用线程池的缘由不只仅只有这些,咱们能够从线程池自身的优势上来进一步了解线程池的好处;服务器
线程池的好处多线程
1:线程和任务分离,提高线程重用性;
2:控制线程并发数量,下降服务器压力,统一管理全部线程;
3:提高系统响应速度,假如建立线程用的时间为T1,执行任务用的时间为T2,销毁线程用的时间为T3,那么使用线程池就免去了T1和T3的时间;并发
ThreadPoolExecutor构造ide
public ThreadPoolExecutor(int corePoolSize, // 1 int maximumPoolSize, // 2 long keepAliveTime, // 3 TimeUnit unit, // 4 BlockingQueue<Runnable> workQueue, // 5 ThreadFactory threadFactory, // 6 RejectedExecutionHandler handler ) { //7 if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }
快速理解其配置测试
咱们能够经过下面的场景理解ThreadPoolExecutor中的各个参数;
a客户(任务)去银行(线程池)办理业务,但银行刚开始营业,窗口服务员还未就位(至关于线程池中初始线程数量为0),
因而经理(线程池管理者)就安排1号工做人员(建立1号线程执行任务)接待a客户(建立线程);
在a客户业务还没办完时,b客户(任务)又来了,因而经理(线程池管理者)就安排2号工做人员(建立2号线程执行任务)接待b客户(又建立了一个新的线程);假设该银行总共就2个窗口(核心线程数量是2);
紧接着在a,b客户都没有结束的状况下c客户来了,因而经理(线程池管理者)就安排c客户先坐到银行大厅的座位上(空位至关因而任务队列)等候,并告知他: 若是一、2号工做人员空出,c就能够前去办理业务;
此时d客户又到了银行,(工做人员都在忙,大厅座位也满了)因而经理赶忙安排临时工(新建立的线程)在大堂站着,手持pad设备给d客户办理业务;
假如前面的业务都没有结束的时候e客户又来了,此时正式工做人员都上了,临时工也上了,座位也满了(临时工加正式员工的总数量就是最大线程数),
因而经理只能按《超出银行最大接待能力处理办法》(饱和处理机制)拒接接待e客户;
最后,进来办业务的人少了,大厅的临时工空闲时间也超过了1个小时(最大空闲时间),经理就会让这部分空闲的员工人下班.(销毁线程)
可是为了保证银行银行正常工做(有一个allowCoreThreadTimeout变量控制是否容许销毁核心线程,默认false),即便正式工闲着,也不得提早下班,因此一、2号工做人员继续待着(池内保持核心线程数量);this
线程池工做流程图spa
自定义线程池
1:核心线程数(corePoolSize)
核心线程数的设计须要依据任务的处理时间和每秒产生的任务数量来肯定,例如:执行一个任务须要0.1秒,系统百分之80的时间每秒都会产生100个任务,那么要想在1秒内处理完这100个任务,就须要10个线程,此时咱们就能够设计核心线程数为10;固然实际状况不可能这么平均,因此咱们通常按照8020原则设计便可,既按照百分之80的状况设计核心线程数,剩下的百分之20能够利用最大线程数处理;
2:任务队列长度(workQueue)
任务队列长度通常设计为:核心线程数/单个任务执行时间*2便可;例如上面的场景中,核心线程数设计为10,单个任务执行时间为0.1秒,则队列长度能够设计为200;
3:最大线程数(maximumPoolSize)
最大线程数的设计除了须要参照核心线程数的条件外,还须要参照系统每秒产生的最大任务数决定:例如:上述环境中,若是系统每秒最大产生的任务是1000个,那么,最大线程数=(最大任务数-任务队列长度)*单个任务执行时间;既: 最大线程数=(1000-200)*0.1=80个;
4:最大空闲时间(keepAliveTime)
这个参数的设计彻底参考系统运行环境和硬件压力设定,没有固定的参考值,用户能够根据经验和系统产生任务的时间间隔合理设置一个值便可;
说明:
1:编写任务类(MyTask),实现Runnable接口;
2:编写线程类(MyWorker),用于执行任务,须要持有全部任务;
3:编写线程池类(MyThreadPool),包含提交任务,执行任务的能力;
4:编写测试类(MyTest),建立线程池对象,提交多个任务测试;
/** * @author WGR * @create 2020/4/8 -- 20:00 */ public class MyThreadPool { // 1:任务队列 集合 须要控制线程安全问题 private List<Runnable> tasks = Collections.synchronizedList(new LinkedList<>()); //2:当前线程数量 private int num; //3:核心线程数量 private int corePoolSize; //4:最大线程数量 private int maxSize; //5:任务队列的长度 private int workSize; public MyThreadPool(int corePoolSize, int maxSize, int workSize) { this.corePoolSize = corePoolSize; this.maxSize = maxSize; this.workSize = workSize; } //1:提交任务; public void submit(Runnable r){ //判断当前集合中任务的数量,是否超出了最大任务数量 if(tasks.size()>=workSize){ System.out.println("任务:"+r+"被丢弃了..."); }else { tasks.add(r); //执行任务 execTask(r); } } //2:执行任务; private void execTask(Runnable r) { //判断当前线程池中的线程总数量,是否超出了核心数, if(num < corePoolSize){ new MyWorker("核心线程:"+num,tasks).start(); num++; }else if(num < maxSize){ new MyWorker("非核心线程:"+num,tasks).start(); num++; }else { System.out.println("任务:"+r+" 被缓存了..."); } } }
/** * @author WGR * @create 2020/4/8 -- 19:51 */ public class MyTask implements Runnable{ private int id; public MyTask(int id) { this.id = id; } @Override public void run() { String name = Thread.currentThread().getName(); System.out.println("线程:"+name+" 即将执行任务:"+id); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程:"+name+" 完成了任务:"+id); } @Override public String toString() { return "MyTask{" + "id=" + id + '}'; } }
/** * @author WGR * @create 2020/4/8 -- 20:02 */ public class MyTest { public static void main(String[] args) { //1:建立线程池类对象; MyThreadPool pool = new MyThreadPool(4,8,40); //2: 提交多个任务 for (int i = 0; i <100 ; i++) { //3:建立任务对象,并提交给线程池 MyTask my = new MyTask(i); pool.submit(my); } } }
/** * @author WGR * @create 2020/4/8 -- 19:48 */ public class MyWorker extends Thread { private String name;//保存线程的名字 private List<Runnable> tasks; //利用构造方法,给成员变量赋值 public MyWorker(String name, List<Runnable> tasks) { super(name); this.tasks = tasks; } @Override public void run() { //判断集合中是否有任务,只要有,就一直执行任务 while (tasks.size()>0){ Runnable r = tasks.remove(0); r.run(); } } }
结果以下: